From a8f9b1dd359dbbcd63bffe891c5f00a9a2ac1f60 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Wed, 12 May 2021 09:03:57 +0200 Subject: [fixes #2420] Copy vartype.type --- src/utils/lombok/javac/TreeMirrorMaker.java | 2 ++ .../ValAnonymousSubclassSelfReference.java | 9 +++++++++ .../after-ecj/ValAnonymousSubclassSelfReference.java | 16 ++++++++++++++++ .../before/ValAnonymousSubclassSelfReference.java | 12 ++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 test/transform/resource/after-delombok/ValAnonymousSubclassSelfReference.java create mode 100644 test/transform/resource/after-ecj/ValAnonymousSubclassSelfReference.java create mode 100644 test/transform/resource/before/ValAnonymousSubclassSelfReference.java diff --git a/src/utils/lombok/javac/TreeMirrorMaker.java b/src/utils/lombok/javac/TreeMirrorMaker.java index 3cb79412..4b2ad171 100644 --- a/src/utils/lombok/javac/TreeMirrorMaker.java +++ b/src/utils/lombok/javac/TreeMirrorMaker.java @@ -109,6 +109,8 @@ public class TreeMirrorMaker extends TreeCopier { if (wipeSymAndType) { copy.sym = null; copy.type = null; + } else { + if (original.vartype != null) copy.vartype.type = original.vartype.type; } } diff --git a/test/transform/resource/after-delombok/ValAnonymousSubclassSelfReference.java b/test/transform/resource/after-delombok/ValAnonymousSubclassSelfReference.java new file mode 100644 index 00000000..4532ec28 --- /dev/null +++ b/test/transform/resource/after-delombok/ValAnonymousSubclassSelfReference.java @@ -0,0 +1,9 @@ +public class ValAnonymousSubclassSelfReference { + public void test() { + int i = 0; + final int j = 1; + final int k = 2; + new ValAnonymousSubclassSelfReference() { + }; + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValAnonymousSubclassSelfReference.java b/test/transform/resource/after-ecj/ValAnonymousSubclassSelfReference.java new file mode 100644 index 00000000..8a3c7fa8 --- /dev/null +++ b/test/transform/resource/after-ecj/ValAnonymousSubclassSelfReference.java @@ -0,0 +1,16 @@ +import lombok.val; +public class ValAnonymousSubclassSelfReference { + public ValAnonymousSubclassSelfReference() { + super(); + } + public void test() { + int i = 0; + final @val int j = 1; + final @val int k = 2; + new ValAnonymousSubclassSelfReference() { + x() { + super(); + } + }; + } +} \ No newline at end of file diff --git a/test/transform/resource/before/ValAnonymousSubclassSelfReference.java b/test/transform/resource/before/ValAnonymousSubclassSelfReference.java new file mode 100644 index 00000000..6ca05b3c --- /dev/null +++ b/test/transform/resource/before/ValAnonymousSubclassSelfReference.java @@ -0,0 +1,12 @@ +// issue 2420: to trigger the problem 2 var/val, one normal variable and a anonymous self reference is required +import lombok.val; + +public class ValAnonymousSubclassSelfReference { + public void test() { + int i = 0; + val j = 1; + val k = 2; + + new ValAnonymousSubclassSelfReference() { }; + } +} \ No newline at end of file -- cgit From bd00fc4b83dd758c4369c8da97243691c04ac3fa Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Fri, 14 May 2021 23:06:20 +0200 Subject: Copy reference types properly --- src/utils/lombok/javac/TreeMirrorMaker.java | 17 ++++++++++++++++- .../ValAnonymousSubclassSelfReference.java | 10 +++++++++- .../after-ecj/ValAnonymousSubclassSelfReference.java | 9 ++++++++- .../before/ValAnonymousSubclassSelfReference.java | 13 +++++++++++-- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/utils/lombok/javac/TreeMirrorMaker.java b/src/utils/lombok/javac/TreeMirrorMaker.java index 4b2ad171..778e670d 100644 --- a/src/utils/lombok/javac/TreeMirrorMaker.java +++ b/src/utils/lombok/javac/TreeMirrorMaker.java @@ -32,8 +32,10 @@ import lombok.javac.JavacTreeMaker.TypeTag; import com.sun.source.tree.LabeledStatementTree; import com.sun.source.tree.VariableTree; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.TreeCopier; +import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; @@ -110,7 +112,20 @@ public class TreeMirrorMaker extends TreeCopier { copy.sym = null; copy.type = null; } else { - if (original.vartype != null) copy.vartype.type = original.vartype.type; + if (original.vartype != null) { + copy.vartype.type = original.vartype.type; + original.vartype.accept(new TreeScanner() { + @Override public void scan(JCTree tree) { + super.scan(tree); + originalToCopy.get(tree).type = tree.type; + } + + @Override public void visitSelect(JCFieldAccess tree) { + super.visitSelect(tree); + ((JCFieldAccess) originalToCopy.get(tree)).sym = tree.sym; + } + }); + } } } diff --git a/test/transform/resource/after-delombok/ValAnonymousSubclassSelfReference.java b/test/transform/resource/after-delombok/ValAnonymousSubclassSelfReference.java index 4532ec28..a1176a3c 100644 --- a/test/transform/resource/after-delombok/ValAnonymousSubclassSelfReference.java +++ b/test/transform/resource/after-delombok/ValAnonymousSubclassSelfReference.java @@ -1,5 +1,13 @@ +import java.util.Map; +import java.util.HashMap; + public class ValAnonymousSubclassSelfReference { - public void test() { + public void test(T arg) { + T d = arg; + Integer[] e = new Integer[1]; + int[] f = new int[0]; + java.util.Map g = new HashMap(); + Integer h = 0; int i = 0; final int j = 1; final int k = 2; diff --git a/test/transform/resource/after-ecj/ValAnonymousSubclassSelfReference.java b/test/transform/resource/after-ecj/ValAnonymousSubclassSelfReference.java index 8a3c7fa8..12b0f640 100644 --- a/test/transform/resource/after-ecj/ValAnonymousSubclassSelfReference.java +++ b/test/transform/resource/after-ecj/ValAnonymousSubclassSelfReference.java @@ -1,9 +1,16 @@ +import java.util.Map; +import java.util.HashMap; import lombok.val; public class ValAnonymousSubclassSelfReference { public ValAnonymousSubclassSelfReference() { super(); } - public void test() { + public void test(T arg) { + T d = arg; + Integer[] e = new Integer[1]; + int[] f = new int[0]; + java.util.Map g = new HashMap(); + Integer h = 0; int i = 0; final @val int j = 1; final @val int k = 2; diff --git a/test/transform/resource/before/ValAnonymousSubclassSelfReference.java b/test/transform/resource/before/ValAnonymousSubclassSelfReference.java index 6ca05b3c..e7c30c84 100644 --- a/test/transform/resource/before/ValAnonymousSubclassSelfReference.java +++ b/test/transform/resource/before/ValAnonymousSubclassSelfReference.java @@ -1,9 +1,18 @@ -// issue 2420: to trigger the problem 2 var/val, one normal variable and a anonymous self reference is required +// issue 2420: to trigger the problem 2 var/val, at least one normal variable and a anonymous self reference is required +import java.util.Map; +import java.util.HashMap; + import lombok.val; public class ValAnonymousSubclassSelfReference { - public void test() { + public void test(T arg) { + T d = arg; + Integer[] e = new Integer[1]; + int[] f = new int[0]; + java.util.Map g = new HashMap(); + Integer h = 0; int i = 0; + val j = 1; val k = 2; -- cgit From 60f575496b3184c2279e9dba470097ed164d5adf Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Sat, 29 May 2021 18:49:05 +0200 Subject: [fixes #2838] Handle anonymous classes properly Generated qualified names (e.g. Outer.Inner) now stop at anonymous classes instead of adding an empty part. All handlers that add static fields/methods/types now add error messages instead of generating invalid code. --- .../eclipse/handlers/EclipseHandlerUtil.java | 24 +++++++++- .../lombok/eclipse/handlers/HandleBuilder.java | 5 ++ .../eclipse/handlers/HandleEqualsAndHashCode.java | 9 ++-- .../eclipse/handlers/HandleFieldNameConstants.java | 14 +++--- src/core/lombok/eclipse/handlers/HandleLog.java | 5 ++ .../eclipse/handlers/HandleSuperBuilder.java | 4 ++ .../lombok/eclipse/handlers/HandleToString.java | 4 +- src/core/lombok/javac/handlers/HandleBuilder.java | 5 ++ .../javac/handlers/HandleEqualsAndHashCode.java | 2 +- .../javac/handlers/HandleFieldNameConstants.java | 14 +++--- src/core/lombok/javac/handlers/HandleLog.java | 5 ++ .../lombok/javac/handlers/HandleSuperBuilder.java | 4 ++ src/core/lombok/javac/handlers/HandleToString.java | 7 ++- .../lombok/javac/handlers/JavacHandlerUtil.java | 25 +++++++++- .../after-delombok/AccessorsInAnonymousClass.java | 22 +++++++++ .../after-delombok/BuilderInAnonymousClass.java | 8 ++++ .../ConstructorsInAnonymousClass.java | 33 +++++++++++++ .../after-delombok/DataInAnonymousClass.java | 56 ++++++++++++++++++++++ .../EqualsAndHashCodeInAnonymousClass.java | 36 ++++++++++++++ .../FieldNameConstantsInAnonymousClass.java | 8 ++++ .../after-delombok/GetterInAnonymousClass.java | 13 +++++ .../after-delombok/GetterLazyInAnonymousClass.java | 24 ++++++++++ .../LoggerSlf4jInAnonymousClass.java | 7 +++ .../after-delombok/SetterInAnonymousClass.java | 13 +++++ .../SuperBuilderInAnonymousClass.java | 12 +++++ .../SynchronizedInAnonymousClass.java | 15 ++++++ .../after-delombok/ToStringInAnonymousClass.java | 14 ++++++ .../UtilityClassInAnonymousClass.java | 8 ++++ .../after-delombok/ValueInAnonymousClass.java | 46 ++++++++++++++++++ .../after-delombok/WithByInAnonymousClass.java | 16 +++++++ .../after-delombok/WithInAnonymousClass.java | 19 ++++++++ .../after-ecj/AccessorsInAnonymousClass.java | 29 +++++++++++ .../after-ecj/BuilderInAnonymousClass.java | 17 +++++++ .../after-ecj/ConstructorsInAnonymousClass.java | 38 +++++++++++++++ .../resource/after-ecj/DataInAnonymousClass.java | 50 +++++++++++++++++++ .../EqualsAndHashCodeInAnonymousClass.java | 41 ++++++++++++++++ .../FieldNameConstantsInAnonymousClass.java | 17 +++++++ .../resource/after-ecj/GetterInAnonymousClass.java | 20 ++++++++ .../after-ecj/GetterLazyInAnonymousClass.java | 34 +++++++++++++ .../after-ecj/LoggerSlf4jInAnonymousClass.java | 16 +++++++ .../resource/after-ecj/SetterInAnonymousClass.java | 20 ++++++++ .../after-ecj/SuperBuilderInAnonymousClass.java | 23 +++++++++ .../after-ecj/SynchronizedInAnonymousClass.java | 23 +++++++++ .../after-ecj/ToStringInAnonymousClass.java | 20 ++++++++ .../after-ecj/UtilityClassInAnonymousClass.java | 17 +++++++ .../resource/after-ecj/ValueInAnonymousClass.java | 43 +++++++++++++++++ .../resource/after-ecj/WithByInAnonymousClass.java | 20 ++++++++ .../resource/after-ecj/WithInAnonymousClass.java | 23 +++++++++ .../resource/before/AccessorsInAnonymousClass.java | 14 ++++++ .../resource/before/BuilderInAnonymousClass.java | 10 ++++ .../before/ConstructorsInAnonymousClass.java | 17 +++++++ .../resource/before/DataInAnonymousClass.java | 10 ++++ .../before/EqualsAndHashCodeInAnonymousClass.java | 10 ++++ .../before/FieldNameConstantsInAnonymousClass.java | 10 ++++ .../resource/before/GetterInAnonymousClass.java | 10 ++++ .../before/GetterLazyInAnonymousClass.java | 10 ++++ .../before/LoggerSlf4jInAnonymousClass.java | 9 ++++ .../resource/before/SetterInAnonymousClass.java | 10 ++++ .../before/SuperBuilderInAnonymousClass.java | 15 ++++++ .../before/SynchronizedInAnonymousClass.java | 12 +++++ .../resource/before/ToStringInAnonymousClass.java | 10 ++++ .../before/UtilityClassInAnonymousClass.java | 10 ++++ .../resource/before/ValueInAnonymousClass.java | 10 ++++ .../resource/before/WithByInAnonymousClass.java | 12 +++++ .../resource/before/WithInAnonymousClass.java | 12 +++++ .../BuilderInAnonymousClass.java.messages | 1 + ...ieldNameConstantsInAnonymousClass.java.messages | 1 + .../LoggerSlf4jInAnonymousClass.java.messages | 1 + .../SuperBuilderInAnonymousClass.java.messages | 2 + .../UtilityClassInAnonymousClass.java.messages | 1 + .../BuilderInAnonymousClass.java.messages | 1 + ...ieldNameConstantsInAnonymousClass.java.messages | 1 + .../LoggerSlf4jInAnonymousClass.java.messages | 1 + .../SuperBuilderInAnonymousClass.java.messages | 2 + .../UtilityClassInAnonymousClass.java.messages | 1 + 75 files changed, 1103 insertions(+), 28 deletions(-) create mode 100644 test/transform/resource/after-delombok/AccessorsInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/BuilderInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/ConstructorsInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/DataInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/EqualsAndHashCodeInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/FieldNameConstantsInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/GetterInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/GetterLazyInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/LoggerSlf4jInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/SetterInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/SuperBuilderInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/SynchronizedInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/ToStringInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/UtilityClassInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/ValueInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/WithByInAnonymousClass.java create mode 100644 test/transform/resource/after-delombok/WithInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/AccessorsInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/BuilderInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/ConstructorsInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/DataInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/EqualsAndHashCodeInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/FieldNameConstantsInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/GetterInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/GetterLazyInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/LoggerSlf4jInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/SetterInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/SuperBuilderInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/SynchronizedInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/ToStringInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/UtilityClassInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/ValueInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/WithByInAnonymousClass.java create mode 100644 test/transform/resource/after-ecj/WithInAnonymousClass.java create mode 100644 test/transform/resource/before/AccessorsInAnonymousClass.java create mode 100644 test/transform/resource/before/BuilderInAnonymousClass.java create mode 100644 test/transform/resource/before/ConstructorsInAnonymousClass.java create mode 100644 test/transform/resource/before/DataInAnonymousClass.java create mode 100644 test/transform/resource/before/EqualsAndHashCodeInAnonymousClass.java create mode 100644 test/transform/resource/before/FieldNameConstantsInAnonymousClass.java create mode 100644 test/transform/resource/before/GetterInAnonymousClass.java create mode 100644 test/transform/resource/before/GetterLazyInAnonymousClass.java create mode 100644 test/transform/resource/before/LoggerSlf4jInAnonymousClass.java create mode 100644 test/transform/resource/before/SetterInAnonymousClass.java create mode 100644 test/transform/resource/before/SuperBuilderInAnonymousClass.java create mode 100644 test/transform/resource/before/SynchronizedInAnonymousClass.java create mode 100644 test/transform/resource/before/ToStringInAnonymousClass.java create mode 100644 test/transform/resource/before/UtilityClassInAnonymousClass.java create mode 100644 test/transform/resource/before/ValueInAnonymousClass.java create mode 100644 test/transform/resource/before/WithByInAnonymousClass.java create mode 100644 test/transform/resource/before/WithInAnonymousClass.java create mode 100644 test/transform/resource/messages-delombok/BuilderInAnonymousClass.java.messages create mode 100644 test/transform/resource/messages-delombok/FieldNameConstantsInAnonymousClass.java.messages create mode 100644 test/transform/resource/messages-delombok/LoggerSlf4jInAnonymousClass.java.messages create mode 100644 test/transform/resource/messages-delombok/SuperBuilderInAnonymousClass.java.messages create mode 100644 test/transform/resource/messages-delombok/UtilityClassInAnonymousClass.java.messages create mode 100644 test/transform/resource/messages-ecj/BuilderInAnonymousClass.java.messages create mode 100644 test/transform/resource/messages-ecj/FieldNameConstantsInAnonymousClass.java.messages create mode 100644 test/transform/resource/messages-ecj/LoggerSlf4jInAnonymousClass.java.messages create mode 100644 test/transform/resource/messages-ecj/SuperBuilderInAnonymousClass.java.messages create mode 100644 test/transform/resource/messages-ecj/UtilityClassInAnonymousClass.java.messages diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 5eea980c..a9f435fd 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1042,7 +1042,7 @@ public class EclipseHandlerUtil { res[count] = name; n = parent; - while (n != null && n.getKind() == Kind.TYPE && n.get() instanceof TypeDeclaration) { + while (count > 0) { TypeDeclaration td = (TypeDeclaration) n.get(); res[--count] = td.name; n = n.up(); @@ -2635,6 +2635,13 @@ public class EclipseHandlerUtil { return isTypeAndDoesNotHaveFlags(typeNode, ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | AccRecord); } + /** + * Returns {@code true} if the provided node is an actual class, an enum or a record and not some other type declaration (so, not an annotation definition or interface). + */ + public static boolean isClassEnumOrRecord(EclipseNode typeNode) { + return isTypeAndDoesNotHaveFlags(typeNode, ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation); + } + /** * Returns {@code true} if the provided node is a record declaration (so, not an annotation definition, interface, enum, or plain class). */ @@ -2662,6 +2669,21 @@ public class EclipseHandlerUtil { return (modifiers & flags) == 0; } + /** + * Returns {@code true} if the provided node supports static methods and types (top level or static class) + */ + public static boolean isStaticAllowed(EclipseNode typeNode) { + boolean staticAllowed = true; + + while (typeNode.getKind() != Kind.COMPILATION_UNIT) { + if (!staticAllowed) return false; + + staticAllowed = typeNode.isStatic(); + typeNode = typeNode.up(); + } + return true; + } + public static AbstractVariableDeclaration[] getRecordComponents(TypeDeclaration typeDeclaration) { if (typeDeclaration == null || (typeDeclaration.modifiers & AccRecord) == 0) return null; try { diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index dab774f3..82d3bfcf 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -293,6 +293,11 @@ public class HandleBuilder extends EclipseAnnotationHandler { List nonFinalNonDefaultedFields = null; + if (!isStaticAllowed(upToTypeNode(parent))) { + annotationNode.addError("@Builder is not supported on non-static nested classes."); + return; + } + if (parent.get() instanceof TypeDeclaration) { if (!isClass(parent) && !isRecord(parent)) { annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR); diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index 12a3c315..a5e8dfb5 100755 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -538,14 +538,15 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler { annotationNode.addError("@SuperBuilder is only supported on classes."); return; } + if (!isStaticAllowed(parent)) { + annotationNode.addError("@SuperBuilder is not supported on non-static nested classes."); + return; + } job.parentType = parent; TypeDeclaration td = (TypeDeclaration) parent.get(); diff --git a/src/core/lombok/eclipse/handlers/HandleToString.java b/src/core/lombok/eclipse/handlers/HandleToString.java index 171402b3..05b0e069 100644 --- a/src/core/lombok/eclipse/handlers/HandleToString.java +++ b/src/core/lombok/eclipse/handlers/HandleToString.java @@ -315,7 +315,9 @@ public class HandleToString extends EclipseAnnotationHandler { String typeName = getSingleTypeName(type); EclipseNode upType = type.up(); while (upType.getKind() == Kind.TYPE) { - typeName = getSingleTypeName(upType) + "." + typeName; + String upTypeName = getSingleTypeName(upType); + if (upTypeName.isEmpty()) break; + typeName = upTypeName + "." + typeName; upType = upType.up(); } return typeName; diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index c23dc14c..bb852b55 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -234,6 +234,11 @@ public class HandleBuilder extends JavacAnnotationHandler { ArrayList nonFinalNonDefaultedFields = null; + if (!isStaticAllowed(upToTypeNode(parent))) { + annotationNode.addError("@Builder is not supported on non-static nested classes."); + return; + } + if (parent.get() instanceof JCClassDecl) { if (!isClass(parent) && !isRecord(parent)) { annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR); diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index ffe882d8..dace3521 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -385,7 +385,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler { annotationNode.addError("@SuperBuilder is only supported on classes."); return; } + if (!isStaticAllowed(parent)) { + annotationNode.addError("@SuperBuilder is not supported on non-static nested classes."); + return; + } job.parentType = parent; JCClassDecl td = (JCClassDecl) parent.get(); diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java index 3fc6a4e4..249993ee 100644 --- a/src/core/lombok/javac/handlers/HandleToString.java +++ b/src/core/lombok/javac/handlers/HandleToString.java @@ -44,7 +44,6 @@ import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; import com.sun.tools.javac.tree.JCTree.JCBlock; -import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; @@ -252,10 +251,10 @@ public class HandleToString extends JavacAnnotationHandler { } public static String getTypeName(JavacNode typeNode) { - String typeName = ((JCClassDecl) typeNode.get()).name.toString(); + String typeName = typeNode.getName(); JavacNode upType = typeNode.up(); - while (upType.getKind() == Kind.TYPE) { - typeName = ((JCClassDecl) upType.get()).name.toString() + "." + typeName; + while (upType.getKind() == Kind.TYPE && !upType.getName().isEmpty()) { + typeName = upType.getName() + "." + typeName; upType = upType.up(); } return typeName; diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 78c20d39..8fdf9a7f 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -1286,6 +1286,7 @@ public class JavacHandlerUtil { static Type classEnter(JCTree tree, JavacNode parent) { Enter enter = Enter.instance(parent.getContext()); Env classEnv = enter.getEnv((TypeSymbol) parent.getElement()); + if (classEnv == null) return null; Type type = (Type) Permit.invokeSneaky(classEnter, enter, tree, classEnv); if (type == null) return null; type.complete(); @@ -1902,7 +1903,7 @@ public class JavacHandlerUtil { public static JCExpression namePlusTypeParamsToTypeReference(JavacTreeMaker maker, JavacNode parentType, Name typeName, boolean instance, List params, List annotations) { JCExpression r = null; - if (parentType != null && parentType.getKind() == Kind.TYPE) { + if (parentType != null && parentType.getKind() == Kind.TYPE && !parentType.getName().isEmpty()) { JCClassDecl td = (JCClassDecl) parentType.get(); boolean outerInstance = instance && ((td.mods.flags & Flags.STATIC) == 0); List outerParams = instance ? td.typarams : List.nil(); @@ -1978,6 +1979,13 @@ public class JavacHandlerUtil { return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ANNOTATION | RECORD); } + /** + * Returns {@code true} if the provided node is an actual class, an enum or a record and not some other type declaration (so, not an annotation definition or interface). + */ + public static boolean isClassEnumOrRecord(JavacNode typeNode) { + return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ANNOTATION); + } + /** * Returns {@code true} if the provided node is a record declaration (so, not an annotation definition, interface, enum, or plain class). */ @@ -1994,6 +2002,21 @@ public class JavacHandlerUtil { return (typeDeclflags & flags) == 0; } + /** + * Returns {@code true} if the provided node supports static methods and types (top level or static class) + */ + public static boolean isStaticAllowed(JavacNode typeNode) { + boolean staticAllowed = true; + + while (typeNode.getKind() != Kind.COMPILATION_UNIT) { + if (!staticAllowed) return false; + + staticAllowed = typeNode.isStatic(); + typeNode = typeNode.up(); + } + return true; + } + public static JavacNode upToTypeNode(JavacNode node) { if (node == null) throw new NullPointerException("node"); while ((node != null) && !(node.get() instanceof JCClassDecl)) node = node.up(); diff --git a/test/transform/resource/after-delombok/AccessorsInAnonymousClass.java b/test/transform/resource/after-delombok/AccessorsInAnonymousClass.java new file mode 100644 index 00000000..27fab509 --- /dev/null +++ b/test/transform/resource/after-delombok/AccessorsInAnonymousClass.java @@ -0,0 +1,22 @@ +public class AccessorsInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + + @java.lang.SuppressWarnings("all") + public String string() { + return this.string; + } + + /** + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public Inner string(final String string) { + this.string = string; + return this; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/BuilderInAnonymousClass.java b/test/transform/resource/after-delombok/BuilderInAnonymousClass.java new file mode 100644 index 00000000..4810a0a8 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderInAnonymousClass.java @@ -0,0 +1,8 @@ +public class BuilderInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + } + }; +} diff --git a/test/transform/resource/after-delombok/ConstructorsInAnonymousClass.java b/test/transform/resource/after-delombok/ConstructorsInAnonymousClass.java new file mode 100644 index 00000000..56e96ae3 --- /dev/null +++ b/test/transform/resource/after-delombok/ConstructorsInAnonymousClass.java @@ -0,0 +1,33 @@ +import lombok.NonNull; + +public class ConstructorsInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + @NonNull + private String string2; + + @java.lang.SuppressWarnings("all") + public Inner(final String string, @NonNull final String string2) { + if (string2 == null) { + throw new java.lang.NullPointerException("string2 is marked non-null but is null"); + } + this.string = string; + this.string2 = string2; + } + + @java.lang.SuppressWarnings("all") + public Inner(@NonNull final String string2) { + if (string2 == null) { + throw new java.lang.NullPointerException("string2 is marked non-null but is null"); + } + this.string2 = string2; + } + + @java.lang.SuppressWarnings("all") + public Inner() { + } + } + }; +} diff --git a/test/transform/resource/after-delombok/DataInAnonymousClass.java b/test/transform/resource/after-delombok/DataInAnonymousClass.java new file mode 100644 index 00000000..788d7be5 --- /dev/null +++ b/test/transform/resource/after-delombok/DataInAnonymousClass.java @@ -0,0 +1,56 @@ +public class DataInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + + @java.lang.SuppressWarnings("all") + public Inner() { + } + + @java.lang.SuppressWarnings("all") + public String getString() { + return this.string; + } + + @java.lang.SuppressWarnings("all") + public void setString(final String string) { + this.string = string; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof Inner)) return false; + final Inner other = (Inner) o; + if (!other.canEqual((java.lang.Object) this)) return false; + final java.lang.Object this$string = this.getString(); + final java.lang.Object other$string = other.getString(); + if (this$string == null ? other$string != null : !this$string.equals(other$string)) return false; + return true; + } + + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof Inner; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $string = this.getString(); + result = result * PRIME + ($string == null ? 43 : $string.hashCode()); + return result; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "Inner(string=" + this.getString() + ")"; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeInAnonymousClass.java b/test/transform/resource/after-delombok/EqualsAndHashCodeInAnonymousClass.java new file mode 100644 index 00000000..6f0b5738 --- /dev/null +++ b/test/transform/resource/after-delombok/EqualsAndHashCodeInAnonymousClass.java @@ -0,0 +1,36 @@ +public class EqualsAndHashCodeInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof Inner)) return false; + final Inner other = (Inner) o; + if (!other.canEqual((java.lang.Object) this)) return false; + final java.lang.Object this$string = this.string; + final java.lang.Object other$string = other.string; + if (this$string == null ? other$string != null : !this$string.equals(other$string)) return false; + return true; + } + + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof Inner; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $string = this.string; + result = result * PRIME + ($string == null ? 43 : $string.hashCode()); + return result; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/FieldNameConstantsInAnonymousClass.java b/test/transform/resource/after-delombok/FieldNameConstantsInAnonymousClass.java new file mode 100644 index 00000000..1f7e7d7a --- /dev/null +++ b/test/transform/resource/after-delombok/FieldNameConstantsInAnonymousClass.java @@ -0,0 +1,8 @@ +public class FieldNameConstantsInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + } + }; +} diff --git a/test/transform/resource/after-delombok/GetterInAnonymousClass.java b/test/transform/resource/after-delombok/GetterInAnonymousClass.java new file mode 100644 index 00000000..3c990545 --- /dev/null +++ b/test/transform/resource/after-delombok/GetterInAnonymousClass.java @@ -0,0 +1,13 @@ +public class GetterInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + + @java.lang.SuppressWarnings("all") + public String getString() { + return this.string; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/GetterLazyInAnonymousClass.java b/test/transform/resource/after-delombok/GetterLazyInAnonymousClass.java new file mode 100644 index 00000000..4476e463 --- /dev/null +++ b/test/transform/resource/after-delombok/GetterLazyInAnonymousClass.java @@ -0,0 +1,24 @@ +public class GetterLazyInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private final java.util.concurrent.atomic.AtomicReference string = new java.util.concurrent.atomic.AtomicReference(); + + @java.lang.SuppressWarnings({"all", "unchecked"}) + public String getString() { + java.lang.Object value = this.string.get(); + if (value == null) { + synchronized (this.string) { + value = this.string.get(); + if (value == null) { + final String actualValue = "test"; + value = actualValue == null ? this.string : actualValue; + this.string.set(value); + } + } + } + return (String) (value == this.string ? null : value); + } + } + }; +} diff --git a/test/transform/resource/after-delombok/LoggerSlf4jInAnonymousClass.java b/test/transform/resource/after-delombok/LoggerSlf4jInAnonymousClass.java new file mode 100644 index 00000000..1ec25d92 --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerSlf4jInAnonymousClass.java @@ -0,0 +1,7 @@ +public class LoggerSlf4jInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + } + }; +} diff --git a/test/transform/resource/after-delombok/SetterInAnonymousClass.java b/test/transform/resource/after-delombok/SetterInAnonymousClass.java new file mode 100644 index 00000000..ced2be52 --- /dev/null +++ b/test/transform/resource/after-delombok/SetterInAnonymousClass.java @@ -0,0 +1,13 @@ +public class SetterInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + + @java.lang.SuppressWarnings("all") + public void setString(final String string) { + this.string = string; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/SuperBuilderInAnonymousClass.java b/test/transform/resource/after-delombok/SuperBuilderInAnonymousClass.java new file mode 100644 index 00000000..cc654919 --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderInAnonymousClass.java @@ -0,0 +1,12 @@ +public class SuperBuilderInAnonymousClass { + Object annonymous = new Object() { + + class InnerParent { + private String string; + } + + class InnerChild { + private String string; + } + }; +} diff --git a/test/transform/resource/after-delombok/SynchronizedInAnonymousClass.java b/test/transform/resource/after-delombok/SynchronizedInAnonymousClass.java new file mode 100644 index 00000000..904487a3 --- /dev/null +++ b/test/transform/resource/after-delombok/SynchronizedInAnonymousClass.java @@ -0,0 +1,15 @@ +public class SynchronizedInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + @java.lang.SuppressWarnings("all") + private final java.lang.Object $lock = new java.lang.Object[0]; + + public void foo() { + synchronized (this.$lock) { + String foo = "bar"; + } + } + } + }; +} diff --git a/test/transform/resource/after-delombok/ToStringInAnonymousClass.java b/test/transform/resource/after-delombok/ToStringInAnonymousClass.java new file mode 100644 index 00000000..aa3651bb --- /dev/null +++ b/test/transform/resource/after-delombok/ToStringInAnonymousClass.java @@ -0,0 +1,14 @@ +public class ToStringInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "Inner(string=" + this.string + ")"; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/UtilityClassInAnonymousClass.java b/test/transform/resource/after-delombok/UtilityClassInAnonymousClass.java new file mode 100644 index 00000000..3df9b559 --- /dev/null +++ b/test/transform/resource/after-delombok/UtilityClassInAnonymousClass.java @@ -0,0 +1,8 @@ +public class UtilityClassInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + } + }; +} diff --git a/test/transform/resource/after-delombok/ValueInAnonymousClass.java b/test/transform/resource/after-delombok/ValueInAnonymousClass.java new file mode 100644 index 00000000..5bab4093 --- /dev/null +++ b/test/transform/resource/after-delombok/ValueInAnonymousClass.java @@ -0,0 +1,46 @@ +public class ValueInAnonymousClass { + Object annonymous = new Object() { + + final class Inner { + private final String string; + + @java.lang.SuppressWarnings("all") + public Inner(final String string) { + this.string = string; + } + + @java.lang.SuppressWarnings("all") + public String getString() { + return this.string; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof Inner)) return false; + final Inner other = (Inner) o; + final java.lang.Object this$string = this.getString(); + final java.lang.Object other$string = other.getString(); + if (this$string == null ? other$string != null : !this$string.equals(other$string)) return false; + return true; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $string = this.getString(); + result = result * PRIME + ($string == null ? 43 : $string.hashCode()); + return result; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "Inner(string=" + this.getString() + ")"; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/WithByInAnonymousClass.java b/test/transform/resource/after-delombok/WithByInAnonymousClass.java new file mode 100644 index 00000000..e3c70763 --- /dev/null +++ b/test/transform/resource/after-delombok/WithByInAnonymousClass.java @@ -0,0 +1,16 @@ +public class WithByInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private Inner(String string) { + } + + private String string; + + @java.lang.SuppressWarnings("all") + public Inner withStringBy(final java.util.function.Function transformer) { + return new Inner(transformer.apply(this.string)); + } + } + }; +} diff --git a/test/transform/resource/after-delombok/WithInAnonymousClass.java b/test/transform/resource/after-delombok/WithInAnonymousClass.java new file mode 100644 index 00000000..02490533 --- /dev/null +++ b/test/transform/resource/after-delombok/WithInAnonymousClass.java @@ -0,0 +1,19 @@ +public class WithInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private Inner(String string) { + } + + private String string; + + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + @java.lang.SuppressWarnings("all") + public Inner withString(final String string) { + return this.string == string ? this : new Inner(string); + } + } + }; +} diff --git a/test/transform/resource/after-ecj/AccessorsInAnonymousClass.java b/test/transform/resource/after-ecj/AccessorsInAnonymousClass.java new file mode 100644 index 00000000..34db4f2d --- /dev/null +++ b/test/transform/resource/after-ecj/AccessorsInAnonymousClass.java @@ -0,0 +1,29 @@ +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +public class AccessorsInAnonymousClass { + Object annonymous = new Object() { + @Getter @Setter @Accessors(fluent = true) class Inner { + private String string; + Inner() { + super(); + } + public @java.lang.SuppressWarnings("all") String string() { + return this.string; + } + /** + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") Inner string(final String string) { + this.string = string; + return this; + } + } + x() { + super(); + } + }; + public AccessorsInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/BuilderInAnonymousClass.java b/test/transform/resource/after-ecj/BuilderInAnonymousClass.java new file mode 100644 index 00000000..67660822 --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderInAnonymousClass.java @@ -0,0 +1,17 @@ +import lombok.Builder; +public class BuilderInAnonymousClass { + Object annonymous = new Object() { + @Builder class Inner { + private String string; + Inner() { + super(); + } + } + x() { + super(); + } + }; + public BuilderInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/ConstructorsInAnonymousClass.java b/test/transform/resource/after-ecj/ConstructorsInAnonymousClass.java new file mode 100644 index 00000000..545ab04d --- /dev/null +++ b/test/transform/resource/after-ecj/ConstructorsInAnonymousClass.java @@ -0,0 +1,38 @@ +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +public class ConstructorsInAnonymousClass { + Object annonymous = new Object() { + @AllArgsConstructor @RequiredArgsConstructor @NoArgsConstructor class Inner { + private String string; + private @NonNull String string2; + public @java.lang.SuppressWarnings("all") Inner(final String string, final @NonNull String string2) { + super(); + if ((string2 == null)) + { + throw new java.lang.NullPointerException("string2 is marked non-null but is null"); + } + this.string = string; + this.string2 = string2; + } + public @java.lang.SuppressWarnings("all") Inner(final @NonNull String string2) { + super(); + if ((string2 == null)) + { + throw new java.lang.NullPointerException("string2 is marked non-null but is null"); + } + this.string2 = string2; + } + public @java.lang.SuppressWarnings("all") Inner() { + super(); + } + } + x() { + super(); + } + }; + public ConstructorsInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/DataInAnonymousClass.java b/test/transform/resource/after-ecj/DataInAnonymousClass.java new file mode 100644 index 00000000..c6e22f80 --- /dev/null +++ b/test/transform/resource/after-ecj/DataInAnonymousClass.java @@ -0,0 +1,50 @@ +import lombok.Data; +public class DataInAnonymousClass { + Object annonymous = new Object() { + @Data class Inner { + private String string; + public @java.lang.SuppressWarnings("all") String getString() { + return this.string; + } + public @java.lang.SuppressWarnings("all") void setString(final String string) { + this.string = string; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof Inner))) + return false; + final Inner other = (Inner) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + final java.lang.Object this$string = this.getString(); + final java.lang.Object other$string = other.getString(); + if (((this$string == null) ? (other$string != null) : (! this$string.equals(other$string)))) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof Inner); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $string = this.getString(); + result = ((result * PRIME) + (($string == null) ? 43 : $string.hashCode())); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("Inner(string=" + this.getString()) + ")"); + } + public @java.lang.SuppressWarnings("all") Inner() { + super(); + } + } + x() { + super(); + } + }; + public DataInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/EqualsAndHashCodeInAnonymousClass.java b/test/transform/resource/after-ecj/EqualsAndHashCodeInAnonymousClass.java new file mode 100644 index 00000000..e66850bb --- /dev/null +++ b/test/transform/resource/after-ecj/EqualsAndHashCodeInAnonymousClass.java @@ -0,0 +1,41 @@ +import lombok.EqualsAndHashCode; +public class EqualsAndHashCodeInAnonymousClass { + Object annonymous = new Object() { + @EqualsAndHashCode class Inner { + private String string; + Inner() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof Inner))) + return false; + final Inner other = (Inner) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + final java.lang.Object this$string = this.string; + final java.lang.Object other$string = other.string; + if (((this$string == null) ? (other$string != null) : (! this$string.equals(other$string)))) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof Inner); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $string = this.string; + result = ((result * PRIME) + (($string == null) ? 43 : $string.hashCode())); + return result; + } + } + x() { + super(); + } + }; + public EqualsAndHashCodeInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/FieldNameConstantsInAnonymousClass.java b/test/transform/resource/after-ecj/FieldNameConstantsInAnonymousClass.java new file mode 100644 index 00000000..b04bef51 --- /dev/null +++ b/test/transform/resource/after-ecj/FieldNameConstantsInAnonymousClass.java @@ -0,0 +1,17 @@ +import lombok.experimental.FieldNameConstants; +public class FieldNameConstantsInAnonymousClass { + Object annonymous = new Object() { + @FieldNameConstants class Inner { + private String string; + Inner() { + super(); + } + } + x() { + super(); + } + }; + public FieldNameConstantsInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/GetterInAnonymousClass.java b/test/transform/resource/after-ecj/GetterInAnonymousClass.java new file mode 100644 index 00000000..30e6338d --- /dev/null +++ b/test/transform/resource/after-ecj/GetterInAnonymousClass.java @@ -0,0 +1,20 @@ +import lombok.Getter; +public class GetterInAnonymousClass { + Object annonymous = new Object() { + @Getter class Inner { + private String string; + Inner() { + super(); + } + public @java.lang.SuppressWarnings("all") String getString() { + return this.string; + } + } + x() { + super(); + } + }; + public GetterInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/GetterLazyInAnonymousClass.java b/test/transform/resource/after-ecj/GetterLazyInAnonymousClass.java new file mode 100644 index 00000000..ab8bc599 --- /dev/null +++ b/test/transform/resource/after-ecj/GetterLazyInAnonymousClass.java @@ -0,0 +1,34 @@ +import lombok.Getter; +public class GetterLazyInAnonymousClass { + Object annonymous = new Object() { + class Inner { + private final @Getter(lazy = true) java.util.concurrent.atomic.AtomicReference string = new java.util.concurrent.atomic.AtomicReference(); + Inner() { + super(); + } + public @java.lang.SuppressWarnings({"all", "unchecked"}) String getString() { + java.lang.Object value = this.string.get(); + if ((value == null)) + { + synchronized (this.string) + { + value = this.string.get(); + if ((value == null)) + { + final String actualValue = "test"; + value = ((actualValue == null) ? this.string : actualValue); + this.string.set(value); + } + } + } + return (String) ((value == this.string) ? null : value); + } + } + x() { + super(); + } + }; + public GetterLazyInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/LoggerSlf4jInAnonymousClass.java b/test/transform/resource/after-ecj/LoggerSlf4jInAnonymousClass.java new file mode 100644 index 00000000..0c78a288 --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerSlf4jInAnonymousClass.java @@ -0,0 +1,16 @@ +import lombok.extern.slf4j.Slf4j; +public class LoggerSlf4jInAnonymousClass { + Object annonymous = new Object() { + @Slf4j class Inner { + Inner() { + super(); + } + } + x() { + super(); + } + }; + public LoggerSlf4jInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/SetterInAnonymousClass.java b/test/transform/resource/after-ecj/SetterInAnonymousClass.java new file mode 100644 index 00000000..fc0bf2d8 --- /dev/null +++ b/test/transform/resource/after-ecj/SetterInAnonymousClass.java @@ -0,0 +1,20 @@ +import lombok.Setter; +public class SetterInAnonymousClass { + Object annonymous = new Object() { + @Setter class Inner { + private String string; + Inner() { + super(); + } + public @java.lang.SuppressWarnings("all") void setString(final String string) { + this.string = string; + } + } + x() { + super(); + } + }; + public SetterInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/SuperBuilderInAnonymousClass.java b/test/transform/resource/after-ecj/SuperBuilderInAnonymousClass.java new file mode 100644 index 00000000..238f42df --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderInAnonymousClass.java @@ -0,0 +1,23 @@ +import lombok.experimental.SuperBuilder; +public class SuperBuilderInAnonymousClass { + Object annonymous = new Object() { + @SuperBuilder class InnerParent { + private String string; + InnerParent() { + super(); + } + } + @SuperBuilder class InnerChild { + private String string; + InnerChild() { + super(); + } + } + x() { + super(); + } + }; + public SuperBuilderInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/SynchronizedInAnonymousClass.java b/test/transform/resource/after-ecj/SynchronizedInAnonymousClass.java new file mode 100644 index 00000000..77013f2f --- /dev/null +++ b/test/transform/resource/after-ecj/SynchronizedInAnonymousClass.java @@ -0,0 +1,23 @@ +import lombok.Synchronized; +public class SynchronizedInAnonymousClass { + Object annonymous = new Object() { + class Inner { + private final java.lang.Object $lock = new java.lang.Object[0]; + Inner() { + super(); + } + public @Synchronized void foo() { + synchronized (this.$lock) + { + String foo = "bar"; + } + } + } + x() { + super(); + } + }; + public SynchronizedInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/ToStringInAnonymousClass.java b/test/transform/resource/after-ecj/ToStringInAnonymousClass.java new file mode 100644 index 00000000..02ad2a88 --- /dev/null +++ b/test/transform/resource/after-ecj/ToStringInAnonymousClass.java @@ -0,0 +1,20 @@ +import lombok.ToString; +public class ToStringInAnonymousClass { + Object annonymous = new Object() { + @ToString class Inner { + private String string; + Inner() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("Inner(string=" + this.string) + ")"); + } + } + x() { + super(); + } + }; + public ToStringInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/UtilityClassInAnonymousClass.java b/test/transform/resource/after-ecj/UtilityClassInAnonymousClass.java new file mode 100644 index 00000000..e836636d --- /dev/null +++ b/test/transform/resource/after-ecj/UtilityClassInAnonymousClass.java @@ -0,0 +1,17 @@ +import lombok.experimental.UtilityClass; +public class UtilityClassInAnonymousClass { + Object annonymous = new Object() { + @UtilityClass class Inner { + private String string; + Inner() { + super(); + } + } + x() { + super(); + } + }; + public UtilityClassInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/ValueInAnonymousClass.java b/test/transform/resource/after-ecj/ValueInAnonymousClass.java new file mode 100644 index 00000000..49cf8fc2 --- /dev/null +++ b/test/transform/resource/after-ecj/ValueInAnonymousClass.java @@ -0,0 +1,43 @@ +import lombok.Value; +public class ValueInAnonymousClass { + Object annonymous = new Object() { + final @Value class Inner { + private final String string; + public @java.lang.SuppressWarnings("all") String getString() { + return this.string; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof Inner))) + return false; + final Inner other = (Inner) o; + final java.lang.Object this$string = this.getString(); + final java.lang.Object other$string = other.getString(); + if (((this$string == null) ? (other$string != null) : (! this$string.equals(other$string)))) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $string = this.getString(); + result = ((result * PRIME) + (($string == null) ? 43 : $string.hashCode())); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("Inner(string=" + this.getString()) + ")"); + } + public @java.lang.SuppressWarnings("all") Inner(final String string) { + super(); + this.string = string; + } + } + x() { + super(); + } + }; + public ValueInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/WithByInAnonymousClass.java b/test/transform/resource/after-ecj/WithByInAnonymousClass.java new file mode 100644 index 00000000..1bc3e80c --- /dev/null +++ b/test/transform/resource/after-ecj/WithByInAnonymousClass.java @@ -0,0 +1,20 @@ +import lombok.experimental.WithBy; +public class WithByInAnonymousClass { + Object annonymous = new Object() { + @WithBy class Inner { + private String string; + private Inner(String string) { + super(); + } + public @java.lang.SuppressWarnings("all") Inner withStringBy(final java.util.function.Function transformer) { + return new Inner(transformer.apply(this.string)); + } + } + x() { + super(); + } + }; + public WithByInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/WithInAnonymousClass.java b/test/transform/resource/after-ecj/WithInAnonymousClass.java new file mode 100644 index 00000000..fef96022 --- /dev/null +++ b/test/transform/resource/after-ecj/WithInAnonymousClass.java @@ -0,0 +1,23 @@ +import lombok.With; +public class WithInAnonymousClass { + Object annonymous = new Object() { + @With class Inner { + private String string; + private Inner(String string) { + super(); + } + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + public @java.lang.SuppressWarnings("all") Inner withString(final String string) { + return ((this.string == string) ? this : new Inner(string)); + } + } + x() { + super(); + } + }; + public WithInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/before/AccessorsInAnonymousClass.java b/test/transform/resource/before/AccessorsInAnonymousClass.java new file mode 100644 index 00000000..0bbab1d6 --- /dev/null +++ b/test/transform/resource/before/AccessorsInAnonymousClass.java @@ -0,0 +1,14 @@ +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +public class AccessorsInAnonymousClass { + Object annonymous = new Object() { + @Getter + @Setter + @Accessors(fluent = true) + class Inner { + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/BuilderInAnonymousClass.java b/test/transform/resource/before/BuilderInAnonymousClass.java new file mode 100644 index 00000000..8291e678 --- /dev/null +++ b/test/transform/resource/before/BuilderInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.Builder; + +public class BuilderInAnonymousClass { + Object annonymous = new Object() { + @Builder + class Inner { + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/ConstructorsInAnonymousClass.java b/test/transform/resource/before/ConstructorsInAnonymousClass.java new file mode 100644 index 00000000..b6e78dd3 --- /dev/null +++ b/test/transform/resource/before/ConstructorsInAnonymousClass.java @@ -0,0 +1,17 @@ +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +public class ConstructorsInAnonymousClass { + Object annonymous = new Object() { + @AllArgsConstructor + @RequiredArgsConstructor + @NoArgsConstructor + class Inner { + private String string; + @NonNull + private String string2; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/DataInAnonymousClass.java b/test/transform/resource/before/DataInAnonymousClass.java new file mode 100644 index 00000000..3de5ac0b --- /dev/null +++ b/test/transform/resource/before/DataInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.Data; + +public class DataInAnonymousClass { + Object annonymous = new Object() { + @Data + class Inner { + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/EqualsAndHashCodeInAnonymousClass.java b/test/transform/resource/before/EqualsAndHashCodeInAnonymousClass.java new file mode 100644 index 00000000..0f0995b6 --- /dev/null +++ b/test/transform/resource/before/EqualsAndHashCodeInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.EqualsAndHashCode; + +public class EqualsAndHashCodeInAnonymousClass { + Object annonymous = new Object() { + @EqualsAndHashCode + class Inner { + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/FieldNameConstantsInAnonymousClass.java b/test/transform/resource/before/FieldNameConstantsInAnonymousClass.java new file mode 100644 index 00000000..86325ce5 --- /dev/null +++ b/test/transform/resource/before/FieldNameConstantsInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.experimental.FieldNameConstants; + +public class FieldNameConstantsInAnonymousClass { + Object annonymous = new Object() { + @FieldNameConstants + class Inner { + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/GetterInAnonymousClass.java b/test/transform/resource/before/GetterInAnonymousClass.java new file mode 100644 index 00000000..e8195021 --- /dev/null +++ b/test/transform/resource/before/GetterInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.Getter; + +public class GetterInAnonymousClass { + Object annonymous = new Object() { + @Getter + class Inner { + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/GetterLazyInAnonymousClass.java b/test/transform/resource/before/GetterLazyInAnonymousClass.java new file mode 100644 index 00000000..e342e636 --- /dev/null +++ b/test/transform/resource/before/GetterLazyInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.Getter; + +public class GetterLazyInAnonymousClass { + Object annonymous = new Object() { + class Inner { + @Getter(lazy = true) + private final String string = "test"; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/LoggerSlf4jInAnonymousClass.java b/test/transform/resource/before/LoggerSlf4jInAnonymousClass.java new file mode 100644 index 00000000..4839c7aa --- /dev/null +++ b/test/transform/resource/before/LoggerSlf4jInAnonymousClass.java @@ -0,0 +1,9 @@ +import lombok.extern.slf4j.Slf4j; + +public class LoggerSlf4jInAnonymousClass { + Object annonymous = new Object() { + @Slf4j + class Inner { + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/SetterInAnonymousClass.java b/test/transform/resource/before/SetterInAnonymousClass.java new file mode 100644 index 00000000..1b3c817b --- /dev/null +++ b/test/transform/resource/before/SetterInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.Setter; + +public class SetterInAnonymousClass { + Object annonymous = new Object() { + @Setter + class Inner { + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/SuperBuilderInAnonymousClass.java b/test/transform/resource/before/SuperBuilderInAnonymousClass.java new file mode 100644 index 00000000..bff871aa --- /dev/null +++ b/test/transform/resource/before/SuperBuilderInAnonymousClass.java @@ -0,0 +1,15 @@ +import lombok.experimental.SuperBuilder; + +public class SuperBuilderInAnonymousClass { + Object annonymous = new Object() { + @SuperBuilder + class InnerParent { + private String string; + } + + @SuperBuilder + class InnerChild { + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/SynchronizedInAnonymousClass.java b/test/transform/resource/before/SynchronizedInAnonymousClass.java new file mode 100644 index 00000000..11c623ce --- /dev/null +++ b/test/transform/resource/before/SynchronizedInAnonymousClass.java @@ -0,0 +1,12 @@ +import lombok.Synchronized; + +public class SynchronizedInAnonymousClass { + Object annonymous = new Object() { + class Inner { + @Synchronized + public void foo() { + String foo = "bar"; + } + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/ToStringInAnonymousClass.java b/test/transform/resource/before/ToStringInAnonymousClass.java new file mode 100644 index 00000000..87a7a6c1 --- /dev/null +++ b/test/transform/resource/before/ToStringInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.ToString; + +public class ToStringInAnonymousClass { + Object annonymous = new Object() { + @ToString + class Inner { + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/UtilityClassInAnonymousClass.java b/test/transform/resource/before/UtilityClassInAnonymousClass.java new file mode 100644 index 00000000..41757502 --- /dev/null +++ b/test/transform/resource/before/UtilityClassInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.experimental.UtilityClass; + +public class UtilityClassInAnonymousClass { + Object annonymous = new Object() { + @UtilityClass + class Inner { + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/ValueInAnonymousClass.java b/test/transform/resource/before/ValueInAnonymousClass.java new file mode 100644 index 00000000..c0bde2ab --- /dev/null +++ b/test/transform/resource/before/ValueInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.Value; + +public class ValueInAnonymousClass { + Object annonymous = new Object() { + @Value + class Inner { + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/WithByInAnonymousClass.java b/test/transform/resource/before/WithByInAnonymousClass.java new file mode 100644 index 00000000..b366f168 --- /dev/null +++ b/test/transform/resource/before/WithByInAnonymousClass.java @@ -0,0 +1,12 @@ +import lombok.experimental.WithBy; + +public class WithByInAnonymousClass { + Object annonymous = new Object() { + @WithBy + class Inner { + private Inner(String string) { } + + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/WithInAnonymousClass.java b/test/transform/resource/before/WithInAnonymousClass.java new file mode 100644 index 00000000..daf1bce5 --- /dev/null +++ b/test/transform/resource/before/WithInAnonymousClass.java @@ -0,0 +1,12 @@ +import lombok.With; + +public class WithInAnonymousClass { + Object annonymous = new Object() { + @With + class Inner { + private Inner(String string) { } + + private String string; + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/messages-delombok/BuilderInAnonymousClass.java.messages b/test/transform/resource/messages-delombok/BuilderInAnonymousClass.java.messages new file mode 100644 index 00000000..7607e734 --- /dev/null +++ b/test/transform/resource/messages-delombok/BuilderInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @Builder is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-delombok/FieldNameConstantsInAnonymousClass.java.messages b/test/transform/resource/messages-delombok/FieldNameConstantsInAnonymousClass.java.messages new file mode 100644 index 00000000..b9d4887f --- /dev/null +++ b/test/transform/resource/messages-delombok/FieldNameConstantsInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @FieldNameConstants is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-delombok/LoggerSlf4jInAnonymousClass.java.messages b/test/transform/resource/messages-delombok/LoggerSlf4jInAnonymousClass.java.messages new file mode 100644 index 00000000..d4da9f99 --- /dev/null +++ b/test/transform/resource/messages-delombok/LoggerSlf4jInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @Slf4j is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-delombok/SuperBuilderInAnonymousClass.java.messages b/test/transform/resource/messages-delombok/SuperBuilderInAnonymousClass.java.messages new file mode 100644 index 00000000..f0cf3243 --- /dev/null +++ b/test/transform/resource/messages-delombok/SuperBuilderInAnonymousClass.java.messages @@ -0,0 +1,2 @@ +5 @SuperBuilder is not supported on non-static nested classes. +10 @SuperBuilder is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-delombok/UtilityClassInAnonymousClass.java.messages b/test/transform/resource/messages-delombok/UtilityClassInAnonymousClass.java.messages new file mode 100644 index 00000000..8884e02d --- /dev/null +++ b/test/transform/resource/messages-delombok/UtilityClassInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @UtilityClass automatically makes the class static, however, this class cannot be made static. diff --git a/test/transform/resource/messages-ecj/BuilderInAnonymousClass.java.messages b/test/transform/resource/messages-ecj/BuilderInAnonymousClass.java.messages new file mode 100644 index 00000000..7607e734 --- /dev/null +++ b/test/transform/resource/messages-ecj/BuilderInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @Builder is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-ecj/FieldNameConstantsInAnonymousClass.java.messages b/test/transform/resource/messages-ecj/FieldNameConstantsInAnonymousClass.java.messages new file mode 100644 index 00000000..b9d4887f --- /dev/null +++ b/test/transform/resource/messages-ecj/FieldNameConstantsInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @FieldNameConstants is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-ecj/LoggerSlf4jInAnonymousClass.java.messages b/test/transform/resource/messages-ecj/LoggerSlf4jInAnonymousClass.java.messages new file mode 100644 index 00000000..d4da9f99 --- /dev/null +++ b/test/transform/resource/messages-ecj/LoggerSlf4jInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @Slf4j is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-ecj/SuperBuilderInAnonymousClass.java.messages b/test/transform/resource/messages-ecj/SuperBuilderInAnonymousClass.java.messages new file mode 100644 index 00000000..f0cf3243 --- /dev/null +++ b/test/transform/resource/messages-ecj/SuperBuilderInAnonymousClass.java.messages @@ -0,0 +1,2 @@ +5 @SuperBuilder is not supported on non-static nested classes. +10 @SuperBuilder is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-ecj/UtilityClassInAnonymousClass.java.messages b/test/transform/resource/messages-ecj/UtilityClassInAnonymousClass.java.messages new file mode 100644 index 00000000..8884e02d --- /dev/null +++ b/test/transform/resource/messages-ecj/UtilityClassInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @UtilityClass automatically makes the class static, however, this class cannot be made static. -- cgit From 7585a539e097a2ec60e0cd7e727616c4a7559571 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Sat, 5 Jun 2021 18:44:01 +0200 Subject: [fixes #2863] Clone primitive types --- src/core/lombok/javac/handlers/JavacHandlerUtil.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 78c20d39..45609911 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -106,6 +106,7 @@ import lombok.javac.Javac; import lombok.javac.JavacAugments; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; +import lombok.javac.JavacTreeMaker.TypeTag; import lombok.permit.Permit; /** @@ -2028,7 +2029,9 @@ public class JavacHandlerUtil { private static JCExpression cloneType0(JavacTreeMaker maker, JCTree in) { if (in == null) return null; - if (in instanceof JCPrimitiveTypeTree) return (JCExpression) in; + if (in instanceof JCPrimitiveTypeTree) { + return maker.TypeIdent(TypeTag.typeTag(in)); + } if (in instanceof JCIdent) { return maker.Ident(((JCIdent) in).name); -- cgit From 0f358d38c5e8dc3253503b081c91458c07f71685 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Sun, 6 Jun 2021 10:39:52 +0200 Subject: [testing] Fix javac6 tests --- test/transform/resource/after-delombok/ConstructorsInAnonymousClass.java | 1 + test/transform/resource/after-delombok/WithByInAnonymousClass.java | 1 + test/transform/resource/before/ConstructorsInAnonymousClass.java | 1 + test/transform/resource/before/WithByInAnonymousClass.java | 1 + 4 files changed, 4 insertions(+) diff --git a/test/transform/resource/after-delombok/ConstructorsInAnonymousClass.java b/test/transform/resource/after-delombok/ConstructorsInAnonymousClass.java index 56e96ae3..7483718f 100644 --- a/test/transform/resource/after-delombok/ConstructorsInAnonymousClass.java +++ b/test/transform/resource/after-delombok/ConstructorsInAnonymousClass.java @@ -1,3 +1,4 @@ +//version 8: import lombok.NonNull; public class ConstructorsInAnonymousClass { diff --git a/test/transform/resource/after-delombok/WithByInAnonymousClass.java b/test/transform/resource/after-delombok/WithByInAnonymousClass.java index e3c70763..d84955b6 100644 --- a/test/transform/resource/after-delombok/WithByInAnonymousClass.java +++ b/test/transform/resource/after-delombok/WithByInAnonymousClass.java @@ -1,3 +1,4 @@ +//version 8: public class WithByInAnonymousClass { Object annonymous = new Object() { diff --git a/test/transform/resource/before/ConstructorsInAnonymousClass.java b/test/transform/resource/before/ConstructorsInAnonymousClass.java index b6e78dd3..a74a7f11 100644 --- a/test/transform/resource/before/ConstructorsInAnonymousClass.java +++ b/test/transform/resource/before/ConstructorsInAnonymousClass.java @@ -1,3 +1,4 @@ +//version 8: import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.NonNull; diff --git a/test/transform/resource/before/WithByInAnonymousClass.java b/test/transform/resource/before/WithByInAnonymousClass.java index b366f168..afed6adf 100644 --- a/test/transform/resource/before/WithByInAnonymousClass.java +++ b/test/transform/resource/before/WithByInAnonymousClass.java @@ -1,3 +1,4 @@ +//version 8: import lombok.experimental.WithBy; public class WithByInAnonymousClass { -- cgit From 8af613be13ef21307a94275b67bbfc9c44d84256 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Sun, 15 Aug 2021 09:52:46 +0200 Subject: [fixes #2926] WrittenNamesFinder can now detect generated writes --- src/eclipseAgent/lombok/launch/PatchFixesHider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java index bee30922..30c63cf0 100755 --- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -419,6 +419,7 @@ final class PatchFixesHider { String className = visitor.getClass().getName(); if (!(className.startsWith("org.eclipse.jdt.internal.corext.fix") || className.startsWith("org.eclipse.jdt.internal.ui.fix"))) return false; + if (className.equals("org.eclipse.jdt.internal.corext.fix.VariableDeclarationFixCore$WrittenNamesFinder")) return false; boolean result = false; try { -- cgit From ee9b1128b49841c52a23e42a6e069477fd367db4 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Tue, 17 Aug 2021 08:23:51 +0200 Subject: [fixes #2907] Keep record compact constructor parameters --- src/core/lombok/javac/handlers/HandleNonNull.java | 1 - src/delombok/lombok/delombok/Delombok.java | 4 ++-- test/core/src/lombok/RunTestsViaDelombok.java | 9 ++++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/lombok/javac/handlers/HandleNonNull.java b/src/core/lombok/javac/handlers/HandleNonNull.java index fe66432a..271bedbb 100644 --- a/src/core/lombok/javac/handlers/HandleNonNull.java +++ b/src/core/lombok/javac/handlers/HandleNonNull.java @@ -99,7 +99,6 @@ public class HandleNonNull extends JavacAnnotationHandler { return recursiveSetGeneratedBy(constr, source); } else { existingCtr.mods = mods; - existingCtr.params = params.toList(); existingCtr.body = body; existingCtr = recursiveSetGeneratedBy(existingCtr, source); addSuppressWarningsAll(existingCtr.mods, typeNode, typeNode.getNodeFor(getGeneratedBy(existingCtr)), typeNode.getContext()); diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index 8d39f447..e4f17602 100755 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -43,9 +43,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.IdentityHashMap; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; @@ -733,7 +733,7 @@ public class Delombok { List roots = new ArrayList(); Map baseMap = new IdentityHashMap(); - Set processors = new HashSet(); + Set processors = new LinkedHashSet(); processors.add(new lombok.javac.apt.LombokProcessor()); processors.addAll(additionalAnnotationProcessors); diff --git a/test/core/src/lombok/RunTestsViaDelombok.java b/test/core/src/lombok/RunTestsViaDelombok.java index 23a42c67..e4eb1a30 100644 --- a/test/core/src/lombok/RunTestsViaDelombok.java +++ b/test/core/src/lombok/RunTestsViaDelombok.java @@ -42,7 +42,6 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; import com.sun.source.util.TreePath; @@ -211,8 +210,8 @@ public class RunTestsViaDelombok extends AbstractRunTests { } @Override public void visitVarDef(JCVariableDecl tree) { - // Skip non-field variables - if (!(parent instanceof JCClassDecl)) return; + // Skip local variables + if (!(parent instanceof JCClassDecl || parent instanceof JCMethodDecl)) return; validateSymbol(tree, tree.sym); super.visitVarDef(tree); @@ -222,8 +221,8 @@ public class RunTestsViaDelombok extends AbstractRunTests { if (sym == null) { fail("Missing symbol for " + tree); } - // Skip top level classes - if (sym.owner.getKind() == ElementKind.PACKAGE) return; + // Only classes have enclosed elements, skip everything else + if (!sym.owner.getKind().isClass()) return; if (!sym.owner.getEnclosedElements().contains(sym)) { fail(tree + " not added to parent"); -- cgit From 91859536db8cf4b59235c01474621f81641f9032 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Fri, 9 Jul 2021 09:36:22 +0200 Subject: [jdk17] Add support for default cases --- src/delombok/lombok/delombok/PrettyPrinter.java | 11 +++++++---- src/utils/lombok/javac/JavacTreeMaker.java | 14 +++++++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index bcf3f431..6074a01f 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -1324,13 +1324,16 @@ public class PrettyPrinter extends JCTree.Visitor { @Override public void visitCase(JCCase tree) { // Starting with JDK12, switches allow multiple expressions per case, and can take the form of an expression (preview feature). - List pats = readObject(tree, "pats", null); // JDK 12+ + List pats = readObject(tree, "labels", null); // JDK 17+ if (pats == null) { - JCExpression pat = readObject(tree, "pat", null); // JDK -11 - pats = pat == null ? List.nil() : List.of(pat); + pats = readObject(tree, "pats", null); // JDK 12-17 + } + if (pats == null) { + JCTree pat = readObject(tree, "pat", null); // JDK -11 + pats = pat == null ? List.nil() : List.of(pat); } - if (pats.isEmpty()) { + if (pats.isEmpty() || pats.get(0).getClass().getName().endsWith("$JCDefaultCaseLabel")) { aPrint("default"); } else { aPrint("case "); diff --git a/src/utils/lombok/javac/JavacTreeMaker.java b/src/utils/lombok/javac/JavacTreeMaker.java index 30d71606..d369b4e4 100644 --- a/src/utils/lombok/javac/JavacTreeMaker.java +++ b/src/utils/lombok/javac/JavacTreeMaker.java @@ -607,7 +607,19 @@ public class JavacTreeMaker { public JCCase Case(JCExpression pat, List stats) { if (tryResolve(Case11)) return invoke(Case11, pat, stats); - return invoke(Case12.Case12, Case12.CASE_KIND_STATEMENT, pat == null ? com.sun.tools.javac.util.List.nil() : com.sun.tools.javac.util.List.of(pat), stats, null); + List labels; + if (pat == null) { + labels = tryResolve(DefaultCaseLabel) ? List.of(DefaultCaseLabel()) : List.nil(); + } else { + labels = List.of(pat); + } + return invoke(Case12.Case12, Case12.CASE_KIND_STATEMENT, labels, stats, null); + } + + //javac versions: 17 + private static final MethodId DefaultCaseLabel = MethodId("DefaultCaseLabel", JCTree.class); + public JCTree DefaultCaseLabel() { + return invoke(DefaultCaseLabel); } //javac versions: 6-8 -- cgit From df2601f9dba97ab1a10e7f6be5222968f3335150 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Wed, 18 Aug 2021 09:37:21 +0200 Subject: [jdk17] Add support for guard/parenthesized pattern --- src/delombok/lombok/delombok/PrettyPrinter.java | 24 ++++++++++++++++++- test/pretty/resource/after/Switch17.java | 31 ++++++++++++++++++++++++ test/pretty/resource/before/Switch17.java | 32 +++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 test/pretty/resource/after/Switch17.java create mode 100644 test/pretty/resource/before/Switch17.java diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index 6074a01f..2efe05c2 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -1333,7 +1333,7 @@ public class PrettyPrinter extends JCTree.Visitor { pats = pat == null ? List.nil() : List.of(pat); } - if (pats.isEmpty() || pats.get(0).getClass().getName().endsWith("$JCDefaultCaseLabel")) { + if (pats.isEmpty() || pats.size() == 1 && pats.head.getClass().getName().endsWith("$JCDefaultCaseLabel")) { aPrint("default"); } else { aPrint("case "); @@ -1424,6 +1424,22 @@ public class PrettyPrinter extends JCTree.Visitor { print((Name) readObject(var, "name", null)); } + void printDefaultCase(JCTree tree) { + print("default"); + } + + void printGuardPattern(JCTree tree) { + print((JCTree) readObject(tree, "patt", null)); + print(" && "); + print((JCExpression) readObject(tree, "expr", null)); + } + + void printParenthesizedPattern(JCTree tree) { + print("("); + print((JCTree) readObject(tree, "pattern", null)); + print(")"); + } + @Override public void visitTry(JCTry tree) { aPrint("try "); List resources = readObject(tree, "resources", List.nil()); @@ -1642,6 +1658,12 @@ public class PrettyPrinter extends JCTree.Visitor { printYieldExpression(tree); } else if (className.endsWith("$JCBindingPattern")) { // Introduced as preview in JDK14 printBindingPattern(tree); + } else if (className.endsWith("$JCDefaultCaseLabel")) { // Introduced in JDK17 + printDefaultCase(tree); + } else if (className.endsWith("$JCGuardPattern")) { // Introduced in JDK17 + printGuardPattern(tree); + } else if (className.endsWith("$JCParenthesizedPattern")) { // Introduced in JDK17 + printParenthesizedPattern(tree); } else { throw new AssertionError("Unhandled tree type: " + tree.getClass() + ": " + tree); } diff --git a/test/pretty/resource/after/Switch17.java b/test/pretty/resource/after/Switch17.java new file mode 100644 index 00000000..038f2cd9 --- /dev/null +++ b/test/pretty/resource/after/Switch17.java @@ -0,0 +1,31 @@ +public class Switch17 { + String switchPatternMatching(Object o) { + return switch (o) { + case Integer i -> String.format("int %d", i); + case Long l -> String.format("long %d", l); + case Double d -> String.format("double %f", d); + case String s -> String.format("String %s", s); + default -> o.toString(); + }; + } + + String switchNull(Object o) { + return switch (o) { + case null, default -> "?"; + }; + } + + String switchGuardPattern(Object o) { + return switch (o) { + case String s && s.length() > 1 -> s; + default -> o.toString(); + }; + } + + String switchParenthesizedPattern(Object o) { + return switch (o) { + case (String s) -> s; + default -> o.toString(); + }; + } +} \ No newline at end of file diff --git a/test/pretty/resource/before/Switch17.java b/test/pretty/resource/before/Switch17.java new file mode 100644 index 00000000..17754e82 --- /dev/null +++ b/test/pretty/resource/before/Switch17.java @@ -0,0 +1,32 @@ +// version 17: +public class Switch17 { + String switchPatternMatching(Object o) { + return switch (o) { + case Integer i -> String.format("int %d", i); + case Long l -> String.format("long %d", l); + case Double d -> String.format("double %f", d); + case String s -> String.format("String %s", s); + default -> o.toString(); + }; + } + + String switchNull(Object o) { + return switch (o) { + case null, default -> "?"; + }; + } + + String switchGuardPattern(Object o) { + return switch (o) { + case String s && s.length() > 1 -> s; + default -> o.toString(); + }; + } + + String switchParenthesizedPattern(Object o) { + return switch (o) { + case (String s) -> s; + default -> o.toString(); + }; + } +} -- cgit From 7bea429ea78204365dafde4f69c4e4c2a4b82587 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Wed, 18 Aug 2021 17:37:54 +0200 Subject: [jdk17] Fix ThisParamter test --- test/pretty/resource/after/ThisParameter.java | 6 +++--- test/pretty/resource/before/ThisParameter.java | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/pretty/resource/after/ThisParameter.java b/test/pretty/resource/after/ThisParameter.java index 49452a59..c57916be 100644 --- a/test/pretty/resource/after/ThisParameter.java +++ b/test/pretty/resource/after/ThisParameter.java @@ -16,17 +16,17 @@ class ThisParameter { void runtimeTagged(@RuntimeTagged("runtime") ThisParameter this) { // no content } - @Target(ElementType.PARAMETER) + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.SOURCE) @interface SourceTagged { String value(); } - @Target(ElementType.PARAMETER) + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.CLASS) @interface ClassTagged { String value(); } - @Target(ElementType.PARAMETER) + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) @interface RuntimeTagged { String value(); diff --git a/test/pretty/resource/before/ThisParameter.java b/test/pretty/resource/before/ThisParameter.java index e37651cb..42e4237e 100644 --- a/test/pretty/resource/before/ThisParameter.java +++ b/test/pretty/resource/before/ThisParameter.java @@ -1,4 +1,4 @@ -// version 9: the 'this' param option exists in java8, but is bugged, in that annotations are not allowed on them, even without a @Target. The only purpose of the this param is annotations, so, boy, isn't that a punch in the face? +// version 8: import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -22,19 +22,19 @@ class ThisParameter { // no content } - @Target(ElementType.PARAMETER) + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.SOURCE) @interface SourceTagged { String value(); } - @Target(ElementType.PARAMETER) + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.CLASS) @interface ClassTagged { String value(); } - @Target(ElementType.PARAMETER) + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) @interface RuntimeTagged { String value(); -- cgit From aab88086565355f2740b287cf6a8c28d3329150e Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Wed, 18 Aug 2021 17:59:44 +0200 Subject: [jdk17] Ignore new strictfp warnings --- test/pretty/resource/messages/DefaultMethod.java.messages | 1 + test/pretty/resource/messages/ExoticJava.java.messages | 1 + test/transform/src/lombok/transform/TestSourceFiles.java | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 test/pretty/resource/messages/DefaultMethod.java.messages create mode 100644 test/pretty/resource/messages/ExoticJava.java.messages diff --git a/test/pretty/resource/messages/DefaultMethod.java.messages b/test/pretty/resource/messages/DefaultMethod.java.messages new file mode 100644 index 00000000..766c3d8c --- /dev/null +++ b/test/pretty/resource/messages/DefaultMethod.java.messages @@ -0,0 +1 @@ +OPTIONAL 9 as of release 17, all floating-point expressions are evaluated strictly and 'strictfp' is not required \ No newline at end of file diff --git a/test/pretty/resource/messages/ExoticJava.java.messages b/test/pretty/resource/messages/ExoticJava.java.messages new file mode 100644 index 00000000..68e8d281 --- /dev/null +++ b/test/pretty/resource/messages/ExoticJava.java.messages @@ -0,0 +1 @@ +OPTIONAL 16 as of release 17, all floating-point expressions are evaluated strictly and 'strictfp' is not required \ No newline at end of file diff --git a/test/transform/src/lombok/transform/TestSourceFiles.java b/test/transform/src/lombok/transform/TestSourceFiles.java index ac8b59c1..5fb0614b 100644 --- a/test/transform/src/lombok/transform/TestSourceFiles.java +++ b/test/transform/src/lombok/transform/TestSourceFiles.java @@ -51,7 +51,7 @@ public class TestSourceFiles extends DirectoryRunner.TestParams { @Override public File getMessagesDirectory() { - return null; + return new File("test/pretty/resource/messages"); } @Override -- cgit From f516dd8ab3186121c4a880444302e2f980f393f8 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Wed, 18 Aug 2021 19:36:50 +0200 Subject: [jdk17] Add support for sealed classes --- src/delombok/lombok/delombok/PrettyPrinter.java | 8 ++++++++ src/utils/lombok/javac/Java14Flags.java | 26 ------------------------- src/utils/lombok/javac/Javac.java | 2 ++ test/pretty/resource/after/Sealed.java | 16 +++++++++++++++ test/pretty/resource/before/Sealed.java | 17 ++++++++++++++++ 5 files changed, 43 insertions(+), 26 deletions(-) delete mode 100644 src/utils/lombok/javac/Java14Flags.java create mode 100644 test/pretty/resource/after/Sealed.java create mode 100644 test/pretty/resource/before/Sealed.java diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index 2efe05c2..605b9391 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -545,6 +545,12 @@ public class PrettyPrinter extends JCTree.Visitor { print(tree.implementing, ", "); } + List permitting = readObject(tree, "permitting", List.nil()); + if (permitting.nonEmpty()) { + print(" permits "); + print(permitting, ", "); + } + println(" {"); indent++; printClassMembers(tree.defs, isEnum, isInterface); @@ -1016,6 +1022,8 @@ public class PrettyPrinter extends JCTree.Visitor { if ((v & TRANSIENT) != 0) print("transient "); if ((v & NATIVE) != 0) print("native "); if ((v & ABSTRACT) != 0) print("abstract "); + if ((v & SEALED) != 0) print("sealed "); + if ((v & NON_SEALED) != 0) print("non-sealed "); if ((v & STRICTFP) != 0) print("strictfp "); if ((v & DEFAULT) != 0 && (v & INTERFACE) == 0) print("default "); } diff --git a/src/utils/lombok/javac/Java14Flags.java b/src/utils/lombok/javac/Java14Flags.java deleted file mode 100644 index 0d565dca..00000000 --- a/src/utils/lombok/javac/Java14Flags.java +++ /dev/null @@ -1,26 +0,0 @@ -package lombok.javac; - -public class Java14Flags { - private Java14Flags() { } - - /** - * Flag to indicate that a class is a record. The flag is also used to mark fields that are - * part of the state vector of a record and to mark the canonical constructor - */ - public static final long RECORD = 1L<<61; // ClassSymbols, MethodSymbols and VarSymbols - - /** - * Flag to mark a record constructor as a compact one - */ - public static final long COMPACT_RECORD_CONSTRUCTOR = 1L<<51; // MethodSymbols only - - /** - * Flag to mark a record field that was not initialized in the compact constructor - */ - public static final long UNINITIALIZED_FIELD= 1L<<51; // VarSymbols only - - /** Flag is set for compiler-generated record members, it could be appplied to - * accessors and fields - */ - public static final int GENERATED_MEMBER = 1<<24; // MethodSymbols and VarSymbols -} diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index d9fcc4f2..3fa0fbb5 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -80,6 +80,8 @@ public class Javac { public static final long COMPACT_RECORD_CONSTRUCTOR = 1L << 51; // MethodSymbols (the 'implicit' many-args constructor that records have) public static final long UNINITIALIZED_FIELD = 1L << 51; // VarSymbols (To identify fields that the compact record constructor won't initialize) public static final long GENERATED_MEMBER = 1L << 24; // MethodSymbols, VarSymbols (marks methods and the constructor generated in records) + public static final long SEALED = 1L << 62; // ClassSymbols (Flag to indicate sealed class/interface declaration) + public static final long NON_SEALED = 1L << 63; // ClassSymbols (Flag to indicate that the class/interface was declared with the non-sealed modifier) /** * Returns the version of this java compiler, i.e. the JDK that it shipped in. For example, for javac v1.7, this returns {@code 7}. diff --git a/test/pretty/resource/after/Sealed.java b/test/pretty/resource/after/Sealed.java new file mode 100644 index 00000000..15096034 --- /dev/null +++ b/test/pretty/resource/after/Sealed.java @@ -0,0 +1,16 @@ +public class Sealed { + public abstract sealed class Parent permits Child1, Child2 { + } + + public final class Child1 extends Parent { + } + + public abstract non-sealed class Child2 extends Parent { + } + + public sealed interface SealedInterface permits ChildInterface1 { + } + + public non-sealed interface ChildInterface1 extends SealedInterface { + } +} \ No newline at end of file diff --git a/test/pretty/resource/before/Sealed.java b/test/pretty/resource/before/Sealed.java new file mode 100644 index 00000000..46828627 --- /dev/null +++ b/test/pretty/resource/before/Sealed.java @@ -0,0 +1,17 @@ +// version 15: +public class Sealed { + public abstract sealed class Parent permits Child1, Child2 { + } + + public final class Child1 extends Parent { + } + + public abstract non-sealed class Child2 extends Parent { + } + + public sealed interface SealedInterface permits ChildInterface1 { + } + + public non-sealed interface ChildInterface1 extends SealedInterface { + } +} \ No newline at end of file -- cgit From fdcbaa033d27b344adfea99d8d7bdd99cceacfb3 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Tue, 2 Feb 2021 09:44:36 +0100 Subject: Replace val with native final var in Java >= 10 --- src/core/lombok/eclipse/handlers/HandleVal.java | 20 ++++++++++++++++++-- src/core/lombok/javac/JavacAST.java | 2 +- src/core/lombok/javac/handlers/HandleVal.java | 6 ++++++ src/eclipseAgent/lombok/eclipse/agent/PatchVal.java | 12 ++++++++++++ src/utils/lombok/eclipse/Eclipse.java | 7 +++++-- .../javac/java8/CommentCollectingScannerFactory.java | 3 ++- .../resource/after-delombok/ValSwitchExpression.java | 4 ++-- .../resource/after-delombok/ValToNative.java | 15 +++++++++++++++ .../resource/after-ecj/ValSwitchExpression.java | 4 ++-- test/transform/resource/after-ecj/ValToNative.java | 19 +++++++++++++++++++ test/transform/resource/before/MixGetterVal.java | 1 + .../resource/before/TrickyTypeResolution.java | 1 + .../before/ValAnonymousSubclassWithGenerics.java | 1 + test/transform/resource/before/ValComplex.java | 1 + test/transform/resource/before/ValDefault.java | 2 +- .../resource/before/ValDelegateMethodReference.java | 2 +- test/transform/resource/before/ValErrors.java | 1 + test/transform/resource/before/ValFinal.java | 1 + test/transform/resource/before/ValInBasicFor.java | 1 + test/transform/resource/before/ValInFor.java | 1 + test/transform/resource/before/ValInLambda.java | 2 +- .../resource/before/ValInMultiDeclaration.java | 1 + .../resource/before/ValInTryWithResources.java | 2 +- test/transform/resource/before/ValLambda.java | 2 +- test/transform/resource/before/ValLessSimple.java | 1 + test/transform/resource/before/ValLub.java | 1 + test/transform/resource/before/ValNullInit.java | 1 + .../resource/before/ValOutersWithGenerics.java | 1 + test/transform/resource/before/ValRawType.java | 1 + test/transform/resource/before/ValSimple.java | 1 + test/transform/resource/before/ValToNative.java | 19 +++++++++++++++++++ test/transform/resource/before/ValWeirdTypes.java | 2 +- test/transform/resource/before/ValWithLabel.java | 1 + .../resource/before/ValWithLocalClasses.java | 1 + .../resource/before/ValWithSelfRefGenerics.java | 1 + website/templates/features/val.html | 3 +++ 36 files changed, 128 insertions(+), 16 deletions(-) create mode 100644 test/transform/resource/after-delombok/ValToNative.java create mode 100644 test/transform/resource/after-ecj/ValToNative.java create mode 100644 test/transform/resource/before/ValToNative.java diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java index ac53e27e..0f70e66d 100644 --- a/src/core/lombok/eclipse/handlers/HandleVal.java +++ b/src/core/lombok/eclipse/handlers/HandleVal.java @@ -22,12 +22,14 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.handleFlagUsage; -import static lombok.eclipse.handlers.EclipseHandlerUtil.typeMatches; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + import lombok.ConfigurationKeys; import lombok.val; import lombok.var; import lombok.core.HandlerPriority; import lombok.eclipse.DeferUntilPostDiet; +import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseASTAdapter; import lombok.eclipse.EclipseASTVisitor; import lombok.eclipse.EclipseNode; @@ -39,10 +41,13 @@ import org.eclipse.jdt.internal.compiler.ast.ForStatement; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; /* - * This class just handles 3 basic error cases. The real meat of eclipse 'val' support is in {@code PatchVal} and {@code PatchValEclipse}. + * Java 1-9: This class just handles 3 basic error cases. The real meat of eclipse 'val' support is in {@code PatchVal} and {@code PatchValEclipse}. + * Java 10+: Lombok uses the native 'var' support and transforms 'val' to 'final var'. */ @Provides(EclipseASTVisitor.class) @DeferUntilPostDiet @@ -96,5 +101,16 @@ public class HandleVal extends EclipseASTAdapter { localNode.addError("variable initializer is 'null'"); return; } + + // For Java >= 10 we use native support + if (localNode.getSourceVersion() >= 10) { + if (isVal) { + TypeReference originalType = local.type; + local.type = new SingleTypeReference("var".toCharArray(), Eclipse.pos(local.type)); + local.modifiers |= ClassFileConstants.AccFinal; + local.annotations = addAnnotation(local.type, local.annotations, originalType.getTypeName()); + } + return; + } } } diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index f58de60f..0919c7d4 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -228,7 +228,7 @@ public class JavacAST extends AST { int underscoreIdx = nm.indexOf('_'); if (underscoreIdx > -1) return Integer.parseInt(nm.substring(underscoreIdx + 1)); // assume java9+ - return Integer.parseInt(nm); + return Integer.parseInt(nm.substring(3)); } catch (Exception ignore) {} return 6; } diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java index 0ed831ab..d4fb1027 100644 --- a/src/core/lombok/javac/handlers/HandleVal.java +++ b/src/core/lombok/javac/handlers/HandleVal.java @@ -115,6 +115,12 @@ public class HandleVal extends JavacASTAdapter { local.mods.annotations = local.mods.annotations == null ? List.of(valAnnotation) : local.mods.annotations.append(valAnnotation); } + if (localNode.getSourceVersion() >= 10) { + local.vartype = null; + localNode.getAst().setChanged(); + return; + } + if (JavacResolution.platformHasTargetTyping()) { local.vartype = localNode.getAst().getTreeMaker().Ident(localNode.getAst().toName("___Lombok_VAL_Attrib__")); } else { diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index 774e5b40..824ecefc 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -204,6 +204,8 @@ public class PatchVal { boolean var = isVar(local, scope); if (!(val || var)) return false; + if (hasNativeVarSupport(scope)) return false; + if (val) { StackTraceElement[] st = new Throwable().getStackTrace(); for (int i = 0; i < st.length - 2 && i < 10; i++) { @@ -281,6 +283,14 @@ public class PatchVal { return is(local.type, scope, "lombok.val"); } + private static boolean hasNativeVarSupport(Scope scope) { + long sl = scope.problemReporter().options.sourceLevel >> 16; + long cl = scope.problemReporter().options.complianceLevel >> 16; + if (sl == 0) sl = cl; + if (cl == 0) cl = sl; + return Math.min((int)(sl - 44), (int)(cl - 44)) >= 10; + } + public static boolean handleValForForEach(ForeachStatement forEach, BlockScope scope) { if (forEach.elementVariable == null) return false; @@ -288,6 +298,8 @@ public class PatchVal { boolean var = isVar(forEach.elementVariable, scope); if (!(val || var)) return false; + if (hasNativeVarSupport(scope)) return false; + TypeBinding component = getForEachComponentType(forEach.collection, scope); if (component == null) return false; TypeReference replacement = makeType(component, forEach.elementVariable.type, false); diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java index 8af481b9..0f42ddc6 100644 --- a/src/utils/lombok/eclipse/Eclipse.java +++ b/src/utils/lombok/eclipse/Eclipse.java @@ -224,8 +224,11 @@ public class Eclipse { int highestVersionSoFar = 0; for (Field f : ClassFileConstants.class.getDeclaredFields()) { try { - if (f.getName().startsWith("JDK1_")) { - int thisVersion = Integer.parseInt(f.getName().substring("JDK1_".length())); + if (f.getName().startsWith("JDK")) { + String versionString = f.getName().substring("JDK".length()); + if (versionString.startsWith("1_")) versionString = versionString.substring("1_".length()); + + int thisVersion = Integer.parseInt(versionString); if (thisVersion > highestVersionSoFar) { highestVersionSoFar = thisVersion; latestEcjCompilerVersionConstantCached = (Long) f.get(null); diff --git a/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java b/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java index f29f501b..e625cd8d 100644 --- a/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java +++ b/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java @@ -21,6 +21,7 @@ */ package lombok.javac.java8; +import java.nio.Buffer; import java.nio.CharBuffer; import com.sun.tools.javac.parser.Scanner; @@ -79,7 +80,7 @@ public class CommentCollectingScannerFactory extends ScannerFactory { int limit; if (input instanceof CharBuffer && ((CharBuffer) input).hasArray()) { CharBuffer cb = (CharBuffer) input; - cb.compact().flip(); + ((Buffer)cb.compact()).flip(); array = cb.array(); limit = cb.limit(); } else { diff --git a/test/transform/resource/after-delombok/ValSwitchExpression.java b/test/transform/resource/after-delombok/ValSwitchExpression.java index a8fa9b0f..ba26c137 100644 --- a/test/transform/resource/after-delombok/ValSwitchExpression.java +++ b/test/transform/resource/after-delombok/ValSwitchExpression.java @@ -1,9 +1,9 @@ // version 14: public class ValSwitchExpression { public void method(int arg) { - final int x = switch (arg) { + final var x = switch (arg) { default -> { - final java.lang.String s = "string"; + final var s = "string"; yield arg; } }; diff --git a/test/transform/resource/after-delombok/ValToNative.java b/test/transform/resource/after-delombok/ValToNative.java new file mode 100644 index 00000000..64aff9e5 --- /dev/null +++ b/test/transform/resource/after-delombok/ValToNative.java @@ -0,0 +1,15 @@ +// version 10: +import java.io.IOException; +import java.util.Arrays; + +public class ValToNative { + private void test() throws IOException { + final var intField = 1; + for (final var s : Arrays.asList("1")) { + final var s2 = s; + } + try (var in = getClass().getResourceAsStream("ValToNative.class")) { + final var j = in.read(); + } + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValSwitchExpression.java b/test/transform/resource/after-ecj/ValSwitchExpression.java index 59b503cb..4e848572 100644 --- a/test/transform/resource/after-ecj/ValSwitchExpression.java +++ b/test/transform/resource/after-ecj/ValSwitchExpression.java @@ -5,10 +5,10 @@ public class ValSwitchExpression { super(); } public void method(int arg) { - final @val int x = switch (arg) { + final @val var x = switch (arg) { default -> { - final @val java.lang.String s = "string"; + final @val var s = "string"; yield arg; } }; diff --git a/test/transform/resource/after-ecj/ValToNative.java b/test/transform/resource/after-ecj/ValToNative.java new file mode 100644 index 00000000..2c8d721c --- /dev/null +++ b/test/transform/resource/after-ecj/ValToNative.java @@ -0,0 +1,19 @@ +import java.io.IOException; +import java.util.Arrays; +import lombok.val; +public class ValToNative { + public ValToNative() { + super(); + } + private void test() throws IOException { + final @val var intField = 1; + for (final @val var s : Arrays.asList("1")) + { + final @val var s2 = s; + } + try (final @val var in = getClass().getResourceAsStream("ValToNative.class")) + { + final @val var j = in.read(); + } + } +} \ No newline at end of file diff --git a/test/transform/resource/before/MixGetterVal.java b/test/transform/resource/before/MixGetterVal.java index 3f06b1a8..4568902b 100644 --- a/test/transform/resource/before/MixGetterVal.java +++ b/test/transform/resource/before/MixGetterVal.java @@ -1,3 +1,4 @@ +// version :9 import lombok.Getter; import lombok.val; diff --git a/test/transform/resource/before/TrickyTypeResolution.java b/test/transform/resource/before/TrickyTypeResolution.java index 94d97fe0..7f3866ee 100644 --- a/test/transform/resource/before/TrickyTypeResolution.java +++ b/test/transform/resource/before/TrickyTypeResolution.java @@ -1,3 +1,4 @@ +// version :9 import lombok.*; class TrickyDoNothing { @interface Getter {} diff --git a/test/transform/resource/before/ValAnonymousSubclassWithGenerics.java b/test/transform/resource/before/ValAnonymousSubclassWithGenerics.java index c0f8157a..a434ba9d 100644 --- a/test/transform/resource/before/ValAnonymousSubclassWithGenerics.java +++ b/test/transform/resource/before/ValAnonymousSubclassWithGenerics.java @@ -1,3 +1,4 @@ +// version :9 // issue 205: val inside anonymous inner classes is a bit tricky in javac, this test ensures we don't break it. import java.util.*; import lombok.val; diff --git a/test/transform/resource/before/ValComplex.java b/test/transform/resource/before/ValComplex.java index e20124a2..f1898cfd 100644 --- a/test/transform/resource/before/ValComplex.java +++ b/test/transform/resource/before/ValComplex.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValComplex { diff --git a/test/transform/resource/before/ValDefault.java b/test/transform/resource/before/ValDefault.java index 75124c3c..ded4b074 100644 --- a/test/transform/resource/before/ValDefault.java +++ b/test/transform/resource/before/ValDefault.java @@ -1,4 +1,4 @@ -// version 8: +// version 8:9 interface ValDefault { int size(); diff --git a/test/transform/resource/before/ValDelegateMethodReference.java b/test/transform/resource/before/ValDelegateMethodReference.java index 3d1f082c..8cfc2c33 100644 --- a/test/transform/resource/before/ValDelegateMethodReference.java +++ b/test/transform/resource/before/ValDelegateMethodReference.java @@ -1,4 +1,4 @@ -//version 8: +//version 8:9 //platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. import lombok.Getter; import lombok.Setter; diff --git a/test/transform/resource/before/ValErrors.java b/test/transform/resource/before/ValErrors.java index 87383719..290a1f72 100644 --- a/test/transform/resource/before/ValErrors.java +++ b/test/transform/resource/before/ValErrors.java @@ -1,3 +1,4 @@ +// version :9 // unchanged import lombok.val; diff --git a/test/transform/resource/before/ValFinal.java b/test/transform/resource/before/ValFinal.java index 3c5af366..293c9bce 100644 --- a/test/transform/resource/before/ValFinal.java +++ b/test/transform/resource/before/ValFinal.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValFinal { public void test() { diff --git a/test/transform/resource/before/ValInBasicFor.java b/test/transform/resource/before/ValInBasicFor.java index a109bcd3..b137f0d7 100644 --- a/test/transform/resource/before/ValInBasicFor.java +++ b/test/transform/resource/before/ValInBasicFor.java @@ -1,3 +1,4 @@ +// version :9 // unchanged import lombok.val; diff --git a/test/transform/resource/before/ValInFor.java b/test/transform/resource/before/ValInFor.java index 35332b34..f2c50139 100644 --- a/test/transform/resource/before/ValInFor.java +++ b/test/transform/resource/before/ValInFor.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValInFor { diff --git a/test/transform/resource/before/ValInLambda.java b/test/transform/resource/before/ValInLambda.java index 6750d045..a13c79d2 100644 --- a/test/transform/resource/before/ValInLambda.java +++ b/test/transform/resource/before/ValInLambda.java @@ -1,4 +1,4 @@ -// version 8: +// version 8:9 import java.util.function.Function; import java.util.function.Supplier; diff --git a/test/transform/resource/before/ValInMultiDeclaration.java b/test/transform/resource/before/ValInMultiDeclaration.java index 1c333ebb..0f4e604b 100644 --- a/test/transform/resource/before/ValInMultiDeclaration.java +++ b/test/transform/resource/before/ValInMultiDeclaration.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValInMultiDeclaration { public void test() { diff --git a/test/transform/resource/before/ValInTryWithResources.java b/test/transform/resource/before/ValInTryWithResources.java index a7820062..5c885f79 100644 --- a/test/transform/resource/before/ValInTryWithResources.java +++ b/test/transform/resource/before/ValInTryWithResources.java @@ -1,4 +1,4 @@ -//version 7: +//version 7:9 import lombok.val; import java.io.IOException; diff --git a/test/transform/resource/before/ValLambda.java b/test/transform/resource/before/ValLambda.java index e956bcd3..8f55d222 100644 --- a/test/transform/resource/before/ValLambda.java +++ b/test/transform/resource/before/ValLambda.java @@ -1,4 +1,4 @@ -// version 8: +// version 8:9 import java.io.Serializable; class ValLambda { diff --git a/test/transform/resource/before/ValLessSimple.java b/test/transform/resource/before/ValLessSimple.java index b81cc22c..1ed738cc 100644 --- a/test/transform/resource/before/ValLessSimple.java +++ b/test/transform/resource/before/ValLessSimple.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValLessSimple { diff --git a/test/transform/resource/before/ValLub.java b/test/transform/resource/before/ValLub.java index 509a4f8b..e3b55950 100644 --- a/test/transform/resource/before/ValLub.java +++ b/test/transform/resource/before/ValLub.java @@ -1,3 +1,4 @@ +// version :9 class ValLub { public void easyLub() { java.util.Map m = java.util.Collections.emptyMap(); diff --git a/test/transform/resource/before/ValNullInit.java b/test/transform/resource/before/ValNullInit.java index 649bc0cd..c1610af3 100644 --- a/test/transform/resource/before/ValNullInit.java +++ b/test/transform/resource/before/ValNullInit.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; class ValNullInit { diff --git a/test/transform/resource/before/ValOutersWithGenerics.java b/test/transform/resource/before/ValOutersWithGenerics.java index 1b29d37c..99b71735 100644 --- a/test/transform/resource/before/ValOutersWithGenerics.java +++ b/test/transform/resource/before/ValOutersWithGenerics.java @@ -1,3 +1,4 @@ +// version :9 import java.util.*; import lombok.val; diff --git a/test/transform/resource/before/ValRawType.java b/test/transform/resource/before/ValRawType.java index 3ef8527e..fa47c536 100644 --- a/test/transform/resource/before/ValRawType.java +++ b/test/transform/resource/before/ValRawType.java @@ -1,3 +1,4 @@ +// version :9 import java.util.List; import lombok.val; diff --git a/test/transform/resource/before/ValSimple.java b/test/transform/resource/before/ValSimple.java index 04763be2..5d1911da 100644 --- a/test/transform/resource/before/ValSimple.java +++ b/test/transform/resource/before/ValSimple.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValSimple { diff --git a/test/transform/resource/before/ValToNative.java b/test/transform/resource/before/ValToNative.java new file mode 100644 index 00000000..3b4e6fa8 --- /dev/null +++ b/test/transform/resource/before/ValToNative.java @@ -0,0 +1,19 @@ +// version 10: +import java.io.IOException; +import java.util.Arrays; + +import lombok.val; + +public class ValToNative { + private void test() throws IOException { + val intField = 1; + + for (val s : Arrays.asList("1")) { + val s2 = s; + } + + try (val in = getClass().getResourceAsStream("ValToNative.class")) { + val j = in.read(); + } + } +} diff --git a/test/transform/resource/before/ValWeirdTypes.java b/test/transform/resource/before/ValWeirdTypes.java index f62feca6..710e236b 100644 --- a/test/transform/resource/before/ValWeirdTypes.java +++ b/test/transform/resource/before/ValWeirdTypes.java @@ -1,4 +1,4 @@ -// version 8: In java6/7, lub types worked differently, so, the `arraysAsList` method has a slightly different inferred type there. +// version 8:9 In java6/7, lub types worked differently, so, the `arraysAsList` method has a slightly different inferred type there. import java.math.BigDecimal; import java.util.*; import lombok.val; diff --git a/test/transform/resource/before/ValWithLabel.java b/test/transform/resource/before/ValWithLabel.java index f7c3402a..9e15f937 100644 --- a/test/transform/resource/before/ValWithLabel.java +++ b/test/transform/resource/before/ValWithLabel.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValWithLabel { diff --git a/test/transform/resource/before/ValWithLocalClasses.java b/test/transform/resource/before/ValWithLocalClasses.java index 572a1e7d..0d145aa9 100644 --- a/test/transform/resource/before/ValWithLocalClasses.java +++ b/test/transform/resource/before/ValWithLocalClasses.java @@ -1,3 +1,4 @@ +// version :9 //issue 694: In javac, resolving the RHS (which is what val does) can cause an entire class to be resolved, breaking all usage of val inside that class. This tests that we handle that better. class ValWithLocalClasses1 { { diff --git a/test/transform/resource/before/ValWithSelfRefGenerics.java b/test/transform/resource/before/ValWithSelfRefGenerics.java index d0532606..fdb30d32 100644 --- a/test/transform/resource/before/ValWithSelfRefGenerics.java +++ b/test/transform/resource/before/ValWithSelfRefGenerics.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValWithSelfRefGenerics { public void run(Thing> thing, Thing thing2, java.util.List z) { diff --git a/website/templates/features/val.html b/website/templates/features/val.html index 32a8ffdf..1b137c65 100644 --- a/website/templates/features/val.html +++ b/website/templates/features/val.html @@ -5,6 +5,9 @@

val was introduced in lombok 0.10.

+

+ NEW in Lombok 1.18.22: val gets replaced with final var. +

<@f.overview>

-- cgit From 693601e939e14d73224886c81af3a7513d0a6bfc Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 7 Sep 2021 22:01:50 +0200 Subject: [changelog] add previous commit (val to final var) to changelog --- doc/changelog.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 583736f1..973d86ea 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -3,6 +3,7 @@ Lombok Changelog ### v1.18.21 "Edgy Guinea Pig" * Added the `@StandardException` feature. [Pull Request #2702](https://github.com/projectlombok/lombok/pull/2702). +* IMPROBABLE BREAKING CHANGE: If the underlying compiler and `--release` / `--source` option is 10 or higher, lombok's `val` is now replaced by `final var`. That means compound declarations such as `val x = 10, y = 12;` now fail (lombok's old `val` implementation supported it, javac's `var` does not), but IDE support in particular is more reliable. We decided it was worth the tradeoff. ### v1.18.20 (April 2nd, 2021) * PLATFORM: JDK16 support added. [Issue #2681](https://github.com/projectlombok/lombok/issues/2681). -- cgit From 69c928a629ee66daa175c2eb05d4bbc118cf019c Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 15 Sep 2021 15:55:16 +0200 Subject: [trivial] remove unused import --- src/core/lombok/javac/handlers/HandleSetter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index a0634494..e5b2c062 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -43,7 +43,6 @@ import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCAssign; import com.sun.tools.javac.tree.JCTree.JCBlock; -import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCReturn; -- cgit From 0d7260d0525d68007635df717b2f5520794afbb5 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 15 Sep 2021 15:57:36 +0200 Subject: [fixes #2960] [installer] Fix issue with weird chars in eclipse path Lombok used to attempt to escape 'weird' chars (using a whitelist of chars that need no escaping) when writing out eclipse.ini. However, there _is no_ escaping mechanism available there. Instead, apparently eclipse/java just reads the chars appearing after the `-javaagent:` prefix as literally as possible. Therefore, just.. don't escape, and pray. Spaces, colons, and ats have all been confirmed as working correctly when rendering them literally, and as failing when you attempt to escape them. --- src/installer/lombok/installer/IdeLocation.java | 12 ------------ .../lombok/installer/eclipse/EclipseProductLocation.java | 4 +++- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/installer/lombok/installer/IdeLocation.java b/src/installer/lombok/installer/IdeLocation.java index 6b9a94c6..7cba1e2a 100644 --- a/src/installer/lombok/installer/IdeLocation.java +++ b/src/installer/lombok/installer/IdeLocation.java @@ -64,16 +64,4 @@ public abstract class IdeLocation { return x == null ? p.getPath() : x; } } - - private static final String LEGAL_PATH_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/"; - private static final String LEGAL_PATH_CHARS_WINDOWS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,/;'[]{}!@#$^&()-_+= :\\"; - public static String escapePath(String path) { - StringBuilder out = new StringBuilder(); - String legalChars = OsUtils.getOS() == OsUtils.OS.UNIX ? LEGAL_PATH_CHARS : LEGAL_PATH_CHARS_WINDOWS; - for (char c : path.toCharArray()) { - if (legalChars.indexOf(c) == -1) out.append('\\'); - out.append(c); - } - return out.toString(); - } } diff --git a/src/installer/lombok/installer/eclipse/EclipseProductLocation.java b/src/installer/lombok/installer/eclipse/EclipseProductLocation.java index 73f98a35..4cfd07f5 100644 --- a/src/installer/lombok/installer/eclipse/EclipseProductLocation.java +++ b/src/installer/lombok/installer/eclipse/EclipseProductLocation.java @@ -347,8 +347,10 @@ public final class EclipseProductLocation extends IdeLocation { pathPrefix = pathToLombokJarPrefix; } + // NB: You may be tempted to escape this, but don't; there is no possibility to escape this, but + // eclipse/java reads the string following the colon in 'raw' fashion. Spaces, colons - all works fine. newContents.append(String.format( - "-javaagent:%s", escapePath(pathPrefix + "lombok.jar"))).append(OS_NEWLINE); + "-javaagent:%s", pathPrefix + "lombok.jar")).append(OS_NEWLINE); FileOutputStream fos = new FileOutputStream(eclipseIniPath); try { -- cgit From a7b625652351c290d3bf7cf13106d9bb8861e012 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 16 Sep 2021 02:12:05 +0200 Subject: [changelog] documenting previous commit. --- doc/changelog.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 973d86ea..9f240033 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -2,7 +2,8 @@ Lombok Changelog ---------------- ### v1.18.21 "Edgy Guinea Pig" -* Added the `@StandardException` feature. [Pull Request #2702](https://github.com/projectlombok/lombok/pull/2702). +* PLATFORM: JDK17 support added. [Issue #2898](https://github.com/projectlombok/lombok/issues/2898). +* FEATURE: Added the `@StandardException` feature. [Pull Request #2702](https://github.com/projectlombok/lombok/pull/2702). * IMPROBABLE BREAKING CHANGE: If the underlying compiler and `--release` / `--source` option is 10 or higher, lombok's `val` is now replaced by `final var`. That means compound declarations such as `val x = 10, y = 12;` now fail (lombok's old `val` implementation supported it, javac's `var` does not), but IDE support in particular is more reliable. We decided it was worth the tradeoff. ### v1.18.20 (April 2nd, 2021) -- cgit From be0f950a6555389ab61f891f5105111bc8f4c538 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 16 Sep 2021 12:51:15 +0200 Subject: [issue #2964] Try to look in chocolatey's default installation dir. --- .../lombok/installer/eclipse/StandardProductDescriptor.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java b/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java index 9bd3ae94..a9f55baf 100644 --- a/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java +++ b/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java @@ -157,10 +157,14 @@ public class StandardProductDescriptor implements EclipseProductDescriptor { return base + pathSeparator + alternative.replaceAll("[\\/]", "\\" + pathSeparator); } + private static final String[] BASE_WINDOWS_ROOTS = {"\\", "\\Program Files", "\\Program Files (x86)", "\\ProgramData\\Chocolatey\\lib"}; private static String[] windowsRoots() { String localAppData = windowsLocalAppData(); - if (localAppData == null) return new String[] {"\\", "\\Program Files", "\\Program Files (x86)", USER_HOME}; - return new String[] {"\\", "\\Program Files", "\\Program Files (x86)", USER_HOME, localAppData}; + String[] out = new String[BASE_WINDOWS_ROOTS.length + (localAppData == null ? 1 : 2)]; + System.arraycopy(BASE_WINDOWS_ROOTS, 0, out, 0, BASE_WINDOWS_ROOTS.length); + out[BASE_WINDOWS_ROOTS.length] = USER_HOME; + if (localAppData != null) out[BASE_WINDOWS_ROOTS.length + 1] = localAppData; + return out; } private static String windowsLocalAppData() { -- cgit From d4c4a7a7db0032b7b8d4247405c25c405e9c7dd9 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 16 Sep 2021 19:17:45 +0200 Subject: [issue #2964] fixing the previous commit --- src/installer/lombok/installer/eclipse/StandardProductDescriptor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java b/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java index a9f55baf..365bf7fb 100644 --- a/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java +++ b/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java @@ -35,6 +35,7 @@ import lombok.installer.OsUtils; public class StandardProductDescriptor implements EclipseProductDescriptor { private static final String USER_HOME = System.getProperty("user.home", "."); + private static final String[] BASE_WINDOWS_ROOTS = {"\\", "\\Program Files", "\\Program Files (x86)", "\\ProgramData\\Chocolatey\\lib"}; private static final String[] WINDOWS_ROOTS = windowsRoots(); private static final String[] MAC_ROOTS = {"/Applications", USER_HOME}; private static final String[] UNIX_ROOTS = {USER_HOME}; @@ -157,7 +158,6 @@ public class StandardProductDescriptor implements EclipseProductDescriptor { return base + pathSeparator + alternative.replaceAll("[\\/]", "\\" + pathSeparator); } - private static final String[] BASE_WINDOWS_ROOTS = {"\\", "\\Program Files", "\\Program Files (x86)", "\\ProgramData\\Chocolatey\\lib"}; private static String[] windowsRoots() { String localAppData = windowsLocalAppData(); String[] out = new String[BASE_WINDOWS_ROOTS.length + (localAppData == null ? 1 : 2)]; -- cgit From ba68962cec99cb1411ed7cac259301edc417ebc5 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Sat, 18 Sep 2021 03:35:02 +0200 Subject: [fixes #2736] Add jackson annotation `JsonUnwrapped` to the 'copy to setters' list. --- src/core/lombok/core/handlers/HandlerUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index 19cc5a9e..f88d1679 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -323,6 +323,7 @@ public class HandlerUtil { "com.fasterxml.jackson.annotation.JsonSetter", "com.fasterxml.jackson.annotation.JsonSubTypes", "com.fasterxml.jackson.annotation.JsonTypeInfo", + "com.fasterxml.jackson.annotation.JsonUnwrapped", "com.fasterxml.jackson.annotation.JsonView", "com.fasterxml.jackson.databind.annotation.JsonDeserialize", "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper", -- cgit From c67acc023425bee9c1d0960e38bea94c2254a99a Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Mon, 27 Sep 2021 17:46:20 +0200 Subject: [fixes #2972] Use simple type, move code to patch method --- .../lombok/eclipse/handlers/EclipseHandlerUtil.java | 6 +----- src/core/lombok/eclipse/handlers/HandleVal.java | 19 ++----------------- src/eclipseAgent/lombok/eclipse/agent/PatchVal.java | 13 +++++++++---- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index a9f435fd..b00b8ec1 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -2052,11 +2052,7 @@ public class EclipseHandlerUtil { } int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long)pS << 32 | pE; - long[] poss = new long[annotationTypeFqn.length]; - Arrays.fill(poss, p); - QualifiedTypeReference qualifiedType = new QualifiedTypeReference(annotationTypeFqn, poss); - setGeneratedBy(qualifiedType, source); + TypeReference qualifiedType = generateQualifiedTypeRef(source, annotationTypeFqn); Annotation ann; if (args != null && args.length == 1 && args[0] instanceof Expression) { SingleMemberAnnotation sma = new SingleMemberAnnotation(qualifiedType, pS); diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java index 0f70e66d..1bea5525 100644 --- a/src/core/lombok/eclipse/handlers/HandleVal.java +++ b/src/core/lombok/eclipse/handlers/HandleVal.java @@ -22,14 +22,13 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.handleFlagUsage; -import static lombok.eclipse.handlers.EclipseHandlerUtil.*; +import static lombok.eclipse.handlers.EclipseHandlerUtil.typeMatches; import lombok.ConfigurationKeys; import lombok.val; import lombok.var; import lombok.core.HandlerPriority; import lombok.eclipse.DeferUntilPostDiet; -import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseASTAdapter; import lombok.eclipse.EclipseASTVisitor; import lombok.eclipse.EclipseNode; @@ -41,13 +40,10 @@ import org.eclipse.jdt.internal.compiler.ast.ForStatement; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; -import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeReference; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; /* - * Java 1-9: This class just handles 3 basic error cases. The real meat of eclipse 'val' support is in {@code PatchVal} and {@code PatchValEclipse}. - * Java 10+: Lombok uses the native 'var' support and transforms 'val' to 'final var'. + * This class just handles 3 basic error cases. The real meat of eclipse 'val' support is in {@code PatchVal} and {@code PatchValEclipse} */ @Provides(EclipseASTVisitor.class) @DeferUntilPostDiet @@ -101,16 +97,5 @@ public class HandleVal extends EclipseASTAdapter { localNode.addError("variable initializer is 'null'"); return; } - - // For Java >= 10 we use native support - if (localNode.getSourceVersion() >= 10) { - if (isVal) { - TypeReference originalType = local.type; - local.type = new SingleTypeReference("var".toCharArray(), Eclipse.pos(local.type)); - local.modifiers |= ClassFileConstants.AccFinal; - local.annotations = addAnnotation(local.type, local.annotations, originalType.getTypeName()); - } - return; - } } } diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index 824ecefc..3e96e75d 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -59,8 +59,8 @@ import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; import java.lang.reflect.Field; import static lombok.Lombok.sneakyThrow; -import static lombok.eclipse.Eclipse.poss; -import static lombok.eclipse.handlers.EclipseHandlerUtil.makeType; +import static lombok.eclipse.Eclipse.*; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import static org.eclipse.jdt.core.compiler.CategorizedProblem.CAT_TYPE; public class PatchVal { @@ -204,8 +204,6 @@ public class PatchVal { boolean var = isVar(local, scope); if (!(val || var)) return false; - if (hasNativeVarSupport(scope)) return false; - if (val) { StackTraceElement[] st = new Throwable().getStackTrace(); for (int i = 0; i < st.length - 2 && i < 10; i++) { @@ -239,6 +237,13 @@ public class PatchVal { TypeReference replacement = null; + // Java 10+: Lombok uses the native 'var' support and transforms 'val' to 'final var'. + if (hasNativeVarSupport(scope) && val) { + replacement = new SingleTypeReference("var".toCharArray(), pos(local.type)); + local.initialization = init; + init = null; + } + if (init != null) { if (init.getClass().getName().equals("org.eclipse.jdt.internal.compiler.ast.LambdaExpression")) { return false; -- cgit From 9ef7656a35706f387569189e118076c7279311c3 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Mon, 27 Sep 2021 17:52:34 +0200 Subject: [tests] Exclude recently added 'val' test --- test/transform/resource/before/ValAnonymousSubclassSelfReference.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/transform/resource/before/ValAnonymousSubclassSelfReference.java b/test/transform/resource/before/ValAnonymousSubclassSelfReference.java index e7c30c84..b17c997a 100644 --- a/test/transform/resource/before/ValAnonymousSubclassSelfReference.java +++ b/test/transform/resource/before/ValAnonymousSubclassSelfReference.java @@ -1,3 +1,4 @@ +// version :9 // issue 2420: to trigger the problem 2 var/val, at least one normal variable and a anonymous self reference is required import java.util.Map; import java.util.HashMap; -- cgit From b50aa64f726952723b1a794538d9bb63fc43832d Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Thu, 23 Sep 2021 06:50:28 +0200 Subject: [fixes #2950] Patch language server semantic highlighting --- src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java | 15 ++++++--------- src/eclipseAgent/lombok/launch/PatchFixesHider.java | 15 +++------------ 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 0a11cd7a..05d77b37 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -87,7 +87,6 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { patchHideGeneratedNodes(sm); patchPostCompileHookEclipse(sm); patchFixSourceTypeConverter(sm); - patchDisableLombokForCodeCleanup(sm); patchListRewriteHandleGeneratedMethods(sm); patchSyntaxAndOccurrencesHighlighting(sm); patchSortMembersOperation(sm); @@ -206,14 +205,6 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .build()); } - private static void patchDisableLombokForCodeCleanup(ScriptManager sm) { - sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.exitEarly() - .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTNode", "accept", "void", "org.eclipse.jdt.core.dom.ASTVisitor")) - .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isRefactoringVisitorAndGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.core.dom.ASTVisitor")) - .request(StackRequest.THIS, StackRequest.PARAM1) - .build()); - } - private static void patchListRewriteHandleGeneratedMethods(ScriptManager sm) { sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.replaceMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer$ListRewriter", "rewriteList")) @@ -308,6 +299,12 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { "org.eclipse.jdt.core.dom.SimpleName[]")) .request(StackRequest.RETURN_VALUE).build()); + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTNode", "accept", "void", "org.eclipse.jdt.core.dom.ASTVisitor")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isBlockedVisitorAndGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.core.dom.ASTVisitor")) + .request(StackRequest.THIS, StackRequest.PARAM1) + .build()); + patchRefactorScripts(sm); patchFormatters(sm); } diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java index 30c63cf0..061f3584 100755 --- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -414,23 +414,14 @@ final class PatchFixesHider { return result; } - public static boolean isRefactoringVisitorAndGenerated(org.eclipse.jdt.core.dom.ASTNode node, org.eclipse.jdt.core.dom.ASTVisitor visitor) { + public static boolean isBlockedVisitorAndGenerated(org.eclipse.jdt.core.dom.ASTNode node, org.eclipse.jdt.core.dom.ASTVisitor visitor) { if (visitor == null) return false; String className = visitor.getClass().getName(); - if (!(className.startsWith("org.eclipse.jdt.internal.corext.fix") || className.startsWith("org.eclipse.jdt.internal.ui.fix"))) return false; + if (!(className.startsWith("org.eclipse.jdt.internal.corext.fix") || className.startsWith("org.eclipse.jdt.internal.ui.fix") || className.startsWith("org.eclipse.jdt.ls.core.internal.semantictokens.SemanticTokensVisitor"))) return false; if (className.equals("org.eclipse.jdt.internal.corext.fix.VariableDeclarationFixCore$WrittenNamesFinder")) return false; - boolean result = false; - try { - result = ((Boolean)node.getClass().getField("$isGenerated").get(node)).booleanValue(); - if (!result && node.getParent() != null && node.getParent() instanceof org.eclipse.jdt.core.dom.QualifiedName) { - result = isGenerated(node.getParent()); - } - } catch (Exception e) { - // better to assume it isn't generated - } - return result; + return isGenerated(node); } public static boolean isListRewriteOnGeneratedNode(org.eclipse.jdt.core.dom.rewrite.ListRewrite rewrite) { -- cgit From 07cf64ed66416a4eaa5f6bf8216f307c62dbb0dc Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Thu, 23 Sep 2021 18:09:07 +0200 Subject: Support javadoc copying in ecj language server --- src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java | 14 +++++++++++++- .../lombok/eclipse/agent/EclipsePatcher.java | 8 ++++++++ src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java | 16 ++++++++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index b00b8ec1..f8cde6c8 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -95,6 +95,7 @@ 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.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; @@ -337,6 +338,8 @@ public class EclipseHandlerUtil { public static final Class INTERSECTION_BINDING1, INTERSECTION_BINDING2; public static final Field INTERSECTION_BINDING_TYPES1, INTERSECTION_BINDING_TYPES2; public static final Field TYPE_DECLARATION_RECORD_COMPONENTS; + public static final Class COMPILATION_UNIT; + public static final Method COMPILATION_UNIT_ORIGINAL_FROM_CLONE; static { STRING_LITERAL__LINE_NUMBER = getField(StringLiteral.class, "lineNumber"); ANNOTATION__MEMBER_VALUE_PAIR_NAME = getField(Annotation.class, "memberValuePairName"); @@ -346,6 +349,8 @@ public class EclipseHandlerUtil { INTERSECTION_BINDING_TYPES1 = INTERSECTION_BINDING1 == null ? null : getField(INTERSECTION_BINDING1, "intersectingTypes"); INTERSECTION_BINDING_TYPES2 = INTERSECTION_BINDING2 == null ? null : getField(INTERSECTION_BINDING2, "intersectingTypes"); TYPE_DECLARATION_RECORD_COMPONENTS = getField(TypeDeclaration.class, "recordComponents"); + COMPILATION_UNIT = getClass("org.eclipse.jdt.internal.core.CompilationUnit"); + COMPILATION_UNIT_ORIGINAL_FROM_CLONE = COMPILATION_UNIT == null ? null : Permit.permissiveGetMethod(COMPILATION_UNIT, "originalFromClone"); } public static int reflectInt(Field f, Object o) { @@ -2731,7 +2736,14 @@ public class EclipseHandlerUtil { public static void setDocComment(CompilationUnitDeclaration cud, TypeDeclaration type, ASTNode node, String doc) { if (doc == null) return; - Map docs = EcjAugments.CompilationUnit_javadoc.setIfAbsent(cud.compilationResult.compilationUnit, new HashMap()); + ICompilationUnit compilationUnit = cud.compilationResult.compilationUnit; + if (compilationUnit.getClass().equals(COMPILATION_UNIT)) { + try { + compilationUnit = (ICompilationUnit) Permit.invoke(COMPILATION_UNIT_ORIGINAL_FROM_CLONE, compilationUnit); + } catch (Throwable t) { } + } + + Map docs = EcjAugments.CompilationUnit_javadoc.setIfAbsent(compilationUnit, new HashMap()); if (node instanceof AbstractMethodDeclaration) { AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) node; String signature = getSignature(type, methodDeclaration); diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 05d77b37..fe1c8608 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -892,6 +892,14 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .requestExtra(StackRequest.PARAM1) .build()); + /* This is a copy for the language server implementation that also supports markdown */ + sm.addScript(ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess2", "getHTMLContent", "java.lang.String", "org.eclipse.jdt.core.IJavaElement", "boolean")) + .methodToWrap(new Hook("org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess2", "getHTMLContentFromSource", "java.lang.String", "org.eclipse.jdt.core.IJavaElement")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$Javadoc", "getHTMLContentFromSource", "java.lang.String", "java.lang.String", "org.eclipse.jdt.core.IJavaElement")) + .requestExtra(StackRequest.PARAM1) + .build()); + /* This is an older version that uses IMember instead of IJavaElement */ sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2", "getHTMLContent", "java.lang.String", "org.eclipse.jdt.core.IMember", "boolean")) diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java b/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java index 5b34917e..673c30fd 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Project Lombok Authors. + * Copyright (C) 2020-2021 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 @@ -103,8 +103,9 @@ public class PatchJavadoc { private static class Reflection { private static final Method javadoc2HTML; private static final Method oldJavadoc2HTML; + private static final Method lsJavadoc2HTML; static { - Method a = null, b = null; + Method a = null, b = null, c = null; try { a = Permit.getMethod(JavadocContentAccess2.class, "javadoc2HTML", IMember.class, IJavaElement.class, String.class); @@ -112,9 +113,13 @@ public class PatchJavadoc { try { b = Permit.getMethod(JavadocContentAccess2.class, "javadoc2HTML", IMember.class, String.class); } catch (Throwable t) {} + try { + c = Permit.getMethod(Class.forName("org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess2"), "javadoc2HTML", IMember.class, IJavaElement.class, String.class); + } catch (Throwable t) {} javadoc2HTML = a; oldJavadoc2HTML = b; + lsJavadoc2HTML = c; } private static String javadoc2HTML(IMember member, IJavaElement element, String rawJavadoc) { @@ -125,6 +130,13 @@ public class PatchJavadoc { return null; } } + if (lsJavadoc2HTML != null) { + try { + return (String) lsJavadoc2HTML.invoke(null, member, element, rawJavadoc); + } catch (Throwable t) { + return null; + } + } if (oldJavadoc2HTML != null) { try { return (String) oldJavadoc2HTML.invoke(null, member, rawJavadoc); -- cgit From 2c5754e32a07a70ccec705ced623dce7ce6eb1a0 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 29 Sep 2021 15:25:17 +0200 Subject: [doc] Added some docs on how to debug lombok for various platforms, also updated changelog with recent changes --- doc/changelog.markdown | 3 +++ doc/debug-insights/eclipse.txt | 22 ++++++++++++++++++++++ doc/debug-insights/vscode.txt | 7 +++++++ 3 files changed, 32 insertions(+) create mode 100644 doc/debug-insights/eclipse.txt create mode 100644 doc/debug-insights/vscode.txt diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 9f240033..83e965b5 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -5,6 +5,9 @@ Lombok Changelog * PLATFORM: JDK17 support added. [Issue #2898](https://github.com/projectlombok/lombok/issues/2898). * FEATURE: Added the `@StandardException` feature. [Pull Request #2702](https://github.com/projectlombok/lombok/pull/2702). * IMPROBABLE BREAKING CHANGE: If the underlying compiler and `--release` / `--source` option is 10 or higher, lombok's `val` is now replaced by `final var`. That means compound declarations such as `val x = 10, y = 12;` now fail (lombok's old `val` implementation supported it, javac's `var` does not), but IDE support in particular is more reliable. We decided it was worth the tradeoff. +* BUGFIX: Syntax highlighting in VSCode now works reliably when using lombok. [Issue #2950](https://github.com/projectlombok/lombok/issues/2950). +* BUGFIX: Eclipse's _organize imports_ feature would sometimes remove your `lombok.val` import. [Issue #2972](https://github.com/projectlombok/lombok/issues/2972). + ### v1.18.20 (April 2nd, 2021) * PLATFORM: JDK16 support added. [Issue #2681](https://github.com/projectlombok/lombok/issues/2681). diff --git a/doc/debug-insights/eclipse.txt b/doc/debug-insights/eclipse.txt new file mode 100644 index 00000000..b653594a --- /dev/null +++ b/doc/debug-insights/eclipse.txt @@ -0,0 +1,22 @@ +# How to debug lombok running in eclipse + +## Overview + +Lombok's build scripting can generate a target for you, that lets you run the same eclipse installation inside eclipse, in debug mode. Now you can add breakpoints. + +As lombok is an agent, lombok __must__ load from a jar file. +Nevertheless, lombok can be hot-code-replaced in the debugger. +This works via the loader: The lombok agent has its own classloading architecture, and this architecture is capable of loading lombok's class files from a location of your choosing. Choose the /bin dir from your eclipse project which will help with debugging; eclipse will then be able to apply HCR to the eclipse-running-in-eclipse. Unless there are issues with the loader architecture itself, of course. + +The end goal is that you can make some changes to the lombok sources in your eclipse, then click the 'debug' button, and a new 'test eclipse' starts up using lombok as you wrote it just now. You can now make changes to lombok sources in the original eclipse, hit 'save', and these changes now get automatically applied to the 'test eclipse', as long as you aren't making any changes to signatures (add or remove methods/fields/types, or change return types, param types, etc). + +If you have the sources to eclipse itself, you can open them, set breakpoints, and step through, though be aware that lombok's agent injection system does cause some issues here; we move methods into different classes and eclipse's debugger naturally doesn't understand this, so you can't breakpoint lombok's own patch methods, and stepping through them 'works' but looks bizarre in the debugger as the debugger now thinks your source file clearly cannot possibly match the class file currently running. Just keep going ('step out'), eclipse will figure it out again once you're back in un-instrumented eclipse code. + + +TODO: + +Describe in detail: + +* Which ant tasks to run to create the targets +* How to modify this target, if needed, to point at your bin dir + diff --git a/doc/debug-insights/vscode.txt b/doc/debug-insights/vscode.txt new file mode 100644 index 00000000..efc55619 --- /dev/null +++ b/doc/debug-insights/vscode.txt @@ -0,0 +1,7 @@ +As per @Rawi01's experimenting: + +* VSCode's lombok plugin simply adds the appropriate `-javaagent` options when it fires up the eclipse-based language server. You can also add debug flags here. +* Add the flags `-agentlib:jdwp-transport=dt_socket,server=y,suspend=n,quiet=y,address=12345` to the `settings.json` of the VSCode lombok plugin, and then tell your debugger to attach to localhost:12345. +* Set the property `java.server.launchMode` to `"Standard"`. +* Consider activing the language server debug mode. + -- cgit From d653514d0840b7b2e9034d417f02e8713c8b5a9c Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Wed, 6 Oct 2021 09:26:29 +0200 Subject: Fix syntax highlighting for EqualsAndHashCode --- src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index fe1c8608..328860e3 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -199,6 +199,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .target(new MethodTarget("org.eclipse.jdt.internal.ui.search.OccurrencesFinder", "addUsage")) .target(new MethodTarget("org.eclipse.jdt.internal.ui.search.OccurrencesFinder", "addWrite")) .target(new MethodTarget("org.eclipse.jdt.internal.ui.javaeditor.SemanticHighlightingReconciler$PositionCollector", "visit", "boolean", "org.eclipse.jdt.core.dom.SimpleName")) + .target(new MethodTarget("org.eclipse.jdt.internal.ui.javaeditor.SemanticHighlightingReconciler$PositionCollector", "visitLiteral", "boolean", "org.eclipse.jdt.core.dom.Expression")) .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) .valueMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "returnFalse", "boolean", "java.lang.Object")) .request(StackRequest.PARAM1) -- cgit From 52d078603da0ea9a167c0351e750b7cbd04910f7 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 7 Oct 2021 03:08:13 +0200 Subject: [versioning] pre-release version bump --- doc/changelog.markdown | 2 +- src/core/lombok/core/Version.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 83e965b5..2169901d 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -1,7 +1,7 @@ Lombok Changelog ---------------- -### v1.18.21 "Edgy Guinea Pig" +### v1.18.22 (October 6th, 2021) * PLATFORM: JDK17 support added. [Issue #2898](https://github.com/projectlombok/lombok/issues/2898). * FEATURE: Added the `@StandardException` feature. [Pull Request #2702](https://github.com/projectlombok/lombok/pull/2702). * IMPROBABLE BREAKING CHANGE: If the underlying compiler and `--release` / `--source` option is 10 or higher, lombok's `val` is now replaced by `final var`. That means compound declarations such as `val x = 10, y = 12;` now fail (lombok's old `val` implementation supported it, javac's `var` does not), but IDE support in particular is more reliable. We decided it was worth the tradeoff. diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index eb8ed6e7..3a426e5e 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.java @@ -30,9 +30,9 @@ public class Version { // ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries). // Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example. // Official builds always end in an even number. (Since 0.10.2). - private static final String VERSION = "1.18.21"; - private static final String RELEASE_NAME = "Edgy Guinea Pig"; -// private static final String RELEASE_NAME = "Envious Ferret"; + private static final String VERSION = "1.18.22"; +// private static final String RELEASE_NAME = "Edgy Guinea Pig"; + private static final String RELEASE_NAME = "Envious Ferret"; // Named version history: // Angry Butterfly -- cgit From 4d568ab3ad44eb9e4216a16b111c54d3f101c3bc Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 7 Oct 2021 03:16:03 +0200 Subject: [versioning] post-release version bump --- doc/changelog.markdown | 3 +++ src/core/lombok/core/Version.java | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 2169901d..6f9adbac 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -1,6 +1,9 @@ Lombok Changelog ---------------- +### v1.18.24 "Edgy Guinea Pig" +* No new changes since the release of v1.18.22. + ### v1.18.22 (October 6th, 2021) * PLATFORM: JDK17 support added. [Issue #2898](https://github.com/projectlombok/lombok/issues/2898). * FEATURE: Added the `@StandardException` feature. [Pull Request #2702](https://github.com/projectlombok/lombok/pull/2702). diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index 3a426e5e..dafe17ae 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.java @@ -30,9 +30,9 @@ public class Version { // ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries). // Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example. // Official builds always end in an even number. (Since 0.10.2). - private static final String VERSION = "1.18.22"; -// private static final String RELEASE_NAME = "Edgy Guinea Pig"; - private static final String RELEASE_NAME = "Envious Ferret"; + private static final String VERSION = "1.18.23"; + private static final String RELEASE_NAME = "Edgy Guinea Pig"; +// private static final String RELEASE_NAME = "Envious Ferret"; // Named version history: // Angry Butterfly -- cgit From d2e8370c24ece8f92d7ca417c25c0f7d60ea039a Mon Sep 17 00:00:00 2001 From: ysherwin Date: Sun, 17 Oct 2021 21:17:13 +0300 Subject: Adding a new accessors flag - javaBeansSpecCapitalization --- src/core/lombok/ConfigurationKeys.java | 8 +++ src/core/lombok/core/handlers/HandlerUtil.java | 45 +++++++++---- src/core/lombok/experimental/Accessors.java | 9 +++ .../GetterWithJavaBeansSpecCapitalization.java | 28 ++++++++ .../SetterWithJavaBeansSpecCapitalization.java | 27 ++++++++ .../ValueWithJavaBeansSpecCapitalization.java | 77 ++++++++++++++++++++++ .../WithOnJavaBeansSpecCapitalization.java | 29 ++++++++ .../GetterWithJavaBeansSpecCapitalization.java | 33 ++++++++++ .../SetterWithJavaBeansSpecCapitalization.java | 33 ++++++++++ .../ValueWithJavaBeansSpecCapitalization.java | 58 ++++++++++++++++ .../WithOnJavaBeansSpecCapitalization.java | 25 +++++++ .../GetterWithJavaBeansSpecCapitalization.java | 11 ++++ .../SetterWithJavaBeansSpecCapitalization.java | 11 ++++ .../ValueWithJavaBeansSpecCapitalization.java | 10 +++ .../before/WithOnJavaBeansSpecCapitalization.java | 16 +++++ 15 files changed, 408 insertions(+), 12 deletions(-) create mode 100644 test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/after-delombok/WithOnJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/after-ecj/WithOnJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/before/WithOnJavaBeansSpecCapitalization.java diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index b8cd442a..12307471 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -558,6 +558,14 @@ public class ConfigurationKeys { */ public static final ConfigurationKey ACCESSORS_FLUENT = new ConfigurationKey("lombok.accessors.fluent", "Generate getters and setters using only the field name (no get/set prefix) (default: false).") {}; + /** + * lombok configuration: {@code lombok.accessors.javaBeansSpecCapitalization} = {@code true} | {@code false}. + * + * For any class without an {@code @Accessors} that explicitly defines the {@code javaBeansSpecCapitalization} option, this value is used (default = false). + */ + public static final ConfigurationKey ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION = new ConfigurationKey("lombok.accessors.javaBeansSpecCapitalization", "Generating accessors name according to the JavaBeans Spec (default: false).") {}; + + // ----- ExtensionMethod ----- /** diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index f88d1679..f45481d4 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -585,11 +585,13 @@ public class HandlerUtil { if (Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.GETTER_CONSEQUENT_BOOLEAN))) isBoolean = false; boolean explicitPrefix = accessors != null && accessors.isExplicit("prefix"); boolean explicitFluent = accessors != null && accessors.isExplicit("fluent"); + boolean explicitJavaBeansSpecCapitalization = accessors != null && accessors.isExplicit("javaBeansSpecCapitalization"); - Accessors ac = (explicitPrefix || explicitFluent) ? accessors.getInstance() : null; + Accessors ac = (explicitPrefix || explicitFluent || explicitJavaBeansSpecCapitalization) ? accessors.getInstance() : null; List prefix = explicitPrefix ? Arrays.asList(ac.prefix()) : ast.readConfiguration(ConfigurationKeys.ACCESSORS_PREFIX); boolean fluent = explicitFluent ? ac.fluent() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT)); + boolean javaBeansSpecCapitalization = explicitJavaBeansSpecCapitalization ? ac.javaBeansSpecCapitalization() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION)); fieldName = removePrefix(fieldName, prefix); if (fieldName == null) return null; @@ -602,7 +604,7 @@ public class HandlerUtil { return booleanPrefix + fName.substring(2); } - return buildAccessorName(isBoolean ? booleanPrefix : normalPrefix, fName); + return buildAccessorName(isBoolean ? booleanPrefix : normalPrefix, fName, javaBeansSpecCapitalization); } /** @@ -675,12 +677,14 @@ public class HandlerUtil { boolean explicitPrefix = accessors != null && accessors.isExplicit("prefix"); boolean explicitFluent = accessors != null && accessors.isExplicit("fluent"); + boolean explicitJavaBeansSpecCapitalization = accessors != null && accessors.isExplicit("javaBeansSpecCapitalization"); - Accessors ac = (explicitPrefix || explicitFluent) ? accessors.getInstance() : null; + Accessors ac = (explicitPrefix || explicitFluent || explicitJavaBeansSpecCapitalization) ? accessors.getInstance() : null; List prefix = explicitPrefix ? Arrays.asList(ac.prefix()) : ast.readConfiguration(ConfigurationKeys.ACCESSORS_PREFIX); boolean fluent = explicitFluent ? ac.fluent() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT)); - + boolean javaBeansSpecCapitalization = explicitJavaBeansSpecCapitalization ? ac.javaBeansSpecCapitalization() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION)); + fieldName = removePrefix(fieldName, prefix); if (fieldName == null) return Collections.emptyList(); @@ -691,8 +695,8 @@ public class HandlerUtil { if (adhereToFluent && fluent) { names.add(baseName); } else { - names.add(buildAccessorName(normalPrefix, baseName)); - if (!normalPrefix.equals(booleanPrefix)) names.add(buildAccessorName(booleanPrefix, baseName)); + names.add(buildAccessorName(normalPrefix, baseName, javaBeansSpecCapitalization)); + if (!normalPrefix.equals(booleanPrefix)) names.add(buildAccessorName(booleanPrefix, baseName, javaBeansSpecCapitalization)); } } @@ -723,17 +727,34 @@ public class HandlerUtil { * @return prefix + smartly title-cased suffix. For example, {@code setRunning}. */ public static String buildAccessorName(String prefix, String suffix) { + return buildAccessorName(prefix, suffix, false); + } + + /** + * @param prefix Something like {@code get} or {@code set} or {@code is}. + * @param suffix Something like {@code running}. + * @param shouldFollowJavaBeansSpecCapitalization {@code boolean} that indicates whether the capitalization rules should follow JavaBeanSpec + * @return if shouldFollowJavaBeansSpecCapitalization is {@code true} and name start with only single lowercase letter, returns simple suffix+prefix. For example, {@code setaFieldName} + * otherwise, returns prefix + smartly title-cased suffix. For example, {@code setRunning}. + */ + private static String buildAccessorName(String prefix, String suffix, boolean shouldFollowJavaBeansSpecCapitalization) { if (suffix.length() == 0) return prefix; if (prefix.length() == 0) return suffix; char first = suffix.charAt(0); - if (Character.isLowerCase(first)) { - boolean useUpperCase = suffix.length() > 2 && - (Character.isTitleCase(suffix.charAt(1)) || Character.isUpperCase(suffix.charAt(1))); - suffix = String.format("%s%s", - useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first), - suffix.subSequence(1, suffix.length())); + if (!Character.isLowerCase(first)) { + return String.format("%s%s", prefix, suffix); } + + boolean useUpperCase = suffix.length() > 2 && + (Character.isTitleCase(suffix.charAt(1)) || Character.isUpperCase(suffix.charAt(1))); + if (shouldFollowJavaBeansSpecCapitalization && useUpperCase) { + return String.format("%s%s", prefix, suffix); + } + + suffix = String.format("%s%s", + useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first), + suffix.subSequence(1, suffix.length())); return String.format("%s%s", prefix, suffix); } diff --git a/src/core/lombok/experimental/Accessors.java b/src/core/lombok/experimental/Accessors.java index dc9ae4b0..b3da9a5b 100644 --- a/src/core/lombok/experimental/Accessors.java +++ b/src/core/lombok/experimental/Accessors.java @@ -54,6 +54,15 @@ public @interface Accessors { */ boolean chain() default false; + /** + * If true, accessors names will be capitalized according to JavaBeans capitalization rules. + * If {@code true}, an accessor for a field that starts with a single lowercase letter followed by a capital letter, + * wont capitalize the first letter (named {@code getaFieldName()}, not for example {@code getAFieldName}). + * default: false + * @return + */ + boolean javaBeansSpecCapitalization() default false; + /** * If present, only fields with any of the stated prefixes are given the getter/setter treatment. * Note that a prefix only counts if the next character is NOT a lowercase character or the last diff --git a/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..06026c1b --- /dev/null +++ b/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,28 @@ +class GetterWithoutJavaBeansSpecCapitalization { + int a; + int aField; + @java.lang.SuppressWarnings("all") + public int getA() { + return this.a; + } + @java.lang.SuppressWarnings("all") + public int getAField() { + return this.aField; + } +} + + +class GetterWithJavaBeansSpecCapitalization { + int a; + int aField; + @java.lang.SuppressWarnings("all") + public int getA() { + return this.a; + } + @java.lang.SuppressWarnings("all") + public int getaField() { + return this.aField; + } +} + + diff --git a/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..24c8e883 --- /dev/null +++ b/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,27 @@ +class SetterWithoutJavaBeansSpecCapitalization { + int a; + int aField; + @java.lang.SuppressWarnings("all") + public void setA(final int a) { + this.a = a; + } + @java.lang.SuppressWarnings("all") + public void setAField(final int aField) { + this.aField = aField; + } +} + +class SetterWithJavaBeansSpecCapitalization { + int a; + int aField; + @java.lang.SuppressWarnings("all") + public void setA(final int a) { + this.a = a; + } + @java.lang.SuppressWarnings("all") + public void setaField(final int aField) { + this.aField = aField; + } +} + + diff --git a/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..20139baf --- /dev/null +++ b/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java @@ -0,0 +1,77 @@ +final class ValueWithJavaBeansSpecCapitalization { + private final int aField; + + @java.lang.SuppressWarnings("all") + public ValueWithJavaBeansSpecCapitalization(final int aField) { + this.aField = aField; + } + + @java.lang.SuppressWarnings("all") + public int getaField() { + return this.aField; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof ValueWithJavaBeansSpecCapitalization)) return false; + final ValueWithJavaBeansSpecCapitalization other = (ValueWithJavaBeansSpecCapitalization) o; + if (this.getaField() != other.getaField()) return false; + return true; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.getaField(); + return result; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "ValueWithJavaBeansSpecCapitalization(aField=" + this.getaField() + ")"; + } +} + +final class ValueWithoutJavaBeansSpecCapitalization { + private final int aField; + + @java.lang.SuppressWarnings("all") + public ValueWithoutJavaBeansSpecCapitalization(final int aField) { + this.aField = aField; + } + + @java.lang.SuppressWarnings("all") + public int getAField() { + return this.aField; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof ValueWithoutJavaBeansSpecCapitalization)) return false; + final ValueWithoutJavaBeansSpecCapitalization other = (ValueWithoutJavaBeansSpecCapitalization) o; + if (this.getAField() != other.getAField()) return false; + return true; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.getAField(); + return result; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "ValueWithoutJavaBeansSpecCapitalization(aField=" + this.getAField() + ")"; + } +} diff --git a/test/transform/resource/after-delombok/WithOnJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/WithOnJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..afed2f0e --- /dev/null +++ b/test/transform/resource/after-delombok/WithOnJavaBeansSpecCapitalization.java @@ -0,0 +1,29 @@ +class WithOnJavaBeansSpecCapitalization { + int aField; + + WithOnJavaBeansSpecCapitalization(int aField) { + } + + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + @java.lang.SuppressWarnings("all") + public WithOnJavaBeansSpecCapitalization withaField(final int aField) { + return this.aField == aField ? this : new WithOnJavaBeansSpecCapitalization(aField); + } +} + +class WithOffJavaBeansSpecCapitalization { + int aField; + + WithOffJavaBeansSpecCapitalization(int aField) { + } + + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + @java.lang.SuppressWarnings("all") + public WithOffJavaBeansSpecCapitalization withAField(final int aField) { + return this.aField == aField ? this : new WithOffJavaBeansSpecCapitalization(aField); + } +} diff --git a/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..d605b4ac --- /dev/null +++ b/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,33 @@ +class GetterWithoutJavaBeansSpecCapitalization { + @lombok.Getter int a; + @lombok.Getter int aField; + + GetterWithoutJavaBeansSpecCapitalization() { + super(); + } + + public @java.lang.SuppressWarnings("all") int getA() { + return this.a; + } + + public @java.lang.SuppressWarnings("all") int getAField() { + return this.aField; + } +} + +@lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class GetterWithJavaBeansSpecCapitalization { + @lombok.Getter int a; + @lombok.Getter int aField; + + GetterWithJavaBeansSpecCapitalization() { + super(); + } + + public @java.lang.SuppressWarnings("all") int getA() { + return this.a; + } + + public @java.lang.SuppressWarnings("all") int getaField() { + return this.aField; + } +} diff --git a/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..9907621f --- /dev/null +++ b/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,33 @@ +class SetterWithoutJavaBeansSpecCapitalization { + @lombok.Setter int a; + @lombok.Setter int aField; + + SetterWithoutJavaBeansSpecCapitalization() { + super(); + } + + public @java.lang.SuppressWarnings("all") void setA(final int a) { + this.a = a; + } + + public @java.lang.SuppressWarnings("all") void setAField(final int aField) { + this.aField = aField; + } +} + +@lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class SetterWithJavaBeansSpecCapitalization { + @lombok.Setter int a; + @lombok.Setter int aField; + + SetterWithJavaBeansSpecCapitalization() { + super(); + } + + public @java.lang.SuppressWarnings("all") void setA(final int a) { + this.a = a; + } + + public @java.lang.SuppressWarnings("all") void setaField(final int aField) { + this.aField = aField; + } +} diff --git a/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..f41fcf58 --- /dev/null +++ b/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java @@ -0,0 +1,58 @@ +final @lombok.Value @lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class ValueWithJavaBeansSpecCapitalization { + private final int aField; + public @java.lang.SuppressWarnings("all") int getaField() { + return this.aField; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof ValueWithJavaBeansSpecCapitalization))) + return false; + final ValueWithJavaBeansSpecCapitalization other = (ValueWithJavaBeansSpecCapitalization) o; + if ((this.getaField() != other.getaField())) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.getaField()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("ValueWithJavaBeansSpecCapitalization(aField=" + this.getaField()) + ")"); + } + public @java.lang.SuppressWarnings("all") ValueWithJavaBeansSpecCapitalization(final int aField) { + super(); + this.aField = aField; + } +} +final @lombok.Value class ValueWithoutJavaBeansSpecCapitalization { + private final int aField; + public @java.lang.SuppressWarnings("all") int getAField() { + return this.aField; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof ValueWithoutJavaBeansSpecCapitalization))) + return false; + final ValueWithoutJavaBeansSpecCapitalization other = (ValueWithoutJavaBeansSpecCapitalization) o; + if ((this.getAField() != other.getAField())) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.getAField()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("ValueWithoutJavaBeansSpecCapitalization(aField=" + this.getAField()) + ")"); + } + public @java.lang.SuppressWarnings("all") ValueWithoutJavaBeansSpecCapitalization(final int aField) { + super(); + this.aField = aField; + } +} diff --git a/test/transform/resource/after-ecj/WithOnJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/WithOnJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..06164fe9 --- /dev/null +++ b/test/transform/resource/after-ecj/WithOnJavaBeansSpecCapitalization.java @@ -0,0 +1,25 @@ +@lombok.With @lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class WithOnJavaBeansSpecCapitalization { + int aField; + WithOnJavaBeansSpecCapitalization(int aField) { + super(); + } + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + public @java.lang.SuppressWarnings("all") WithOnJavaBeansSpecCapitalization withaField(final int aField) { + return ((this.aField == aField) ? this : new WithOnJavaBeansSpecCapitalization(aField)); + } +} + +@lombok.With class WithOffJavaBeansSpecCapitalization { + int aField; + WithOffJavaBeansSpecCapitalization(int aField) { + super(); + } + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + public @java.lang.SuppressWarnings("all") WithOffJavaBeansSpecCapitalization withAField(final int aField) { + return ((this.aField == aField) ? this : new WithOffJavaBeansSpecCapitalization(aField)); + } +} diff --git a/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..3c27317c --- /dev/null +++ b/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,11 @@ +class GetterWithoutJavaBeansSpecCapitalization { + @lombok.Getter int a; + @lombok.Getter int aField; +} + +@lombok.experimental.Accessors(javaBeansSpecCapitalization=true) +class GetterWithJavaBeansSpecCapitalization { + @lombok.Getter int a; + @lombok.Getter int aField; +} + diff --git a/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..80a1b4ee --- /dev/null +++ b/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,11 @@ +class SetterWithoutJavaBeansSpecCapitalization { + @lombok.Setter int a; + @lombok.Setter int aField; +} + +@lombok.experimental.Accessors(javaBeansSpecCapitalization=true) +class SetterWithJavaBeansSpecCapitalization { + @lombok.Setter int a; + @lombok.Setter int aField; +} + diff --git a/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..f0044ed9 --- /dev/null +++ b/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java @@ -0,0 +1,10 @@ +@lombok.Value +@lombok.experimental.Accessors(javaBeansSpecCapitalization = true) +class ValueWithJavaBeansSpecCapitalization { + final int aField; +} + +@lombok.Value +class ValueWithoutJavaBeansSpecCapitalization { + final int aField; +} diff --git a/test/transform/resource/before/WithOnJavaBeansSpecCapitalization.java b/test/transform/resource/before/WithOnJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..476fb5a4 --- /dev/null +++ b/test/transform/resource/before/WithOnJavaBeansSpecCapitalization.java @@ -0,0 +1,16 @@ +@lombok.With +@lombok.experimental.Accessors(javaBeansSpecCapitalization = true) +class WithOnJavaBeansSpecCapitalization { + int aField; + + WithOnJavaBeansSpecCapitalization(int aField) { + } +} + +@lombok.With +class WithOffJavaBeansSpecCapitalization { + int aField; + + WithOffJavaBeansSpecCapitalization(int aField) { + } +} -- cgit From 1ae87bad9583620ca79c1f3ede31703cbb95cbc5 Mon Sep 17 00:00:00 2001 From: ysherwin Date: Mon, 18 Oct 2021 19:25:49 +0300 Subject: Adding Yonatan Sherwin to AUTHORS file --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 547246d9..9281c9a9 100755 --- a/AUTHORS +++ b/AUTHORS @@ -49,6 +49,7 @@ Takuya Murakami Thomas Darimont Till Brychcy Victor Williams Stafusa da Silva +Yonatan Sherwin Yun Zhi Lin By adding your name to this list, you grant full and irrevocable copyright and patent indemnity to Project Lombok and all use of Project Lombok in relation to all commits you add to Project Lombok, and you certify that you have the right to do so. -- cgit From dbc67c5c2d0388692f9c9dec02b294da14fd5b56 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 18 Oct 2021 15:44:45 +0200 Subject: [#2693] Review and updates for javabeans-style capitalization lombok.config --- src/core/lombok/ConfigurationKeys.java | 10 +- src/core/lombok/core/AST.java | 18 +++- .../core/configuration/CapitalizationStrategy.java | 52 ++++++++++ .../lombok/core/configuration/FlagUsageType.java | 4 +- src/core/lombok/core/handlers/HandlerUtil.java | 58 ++++++----- .../lombok/eclipse/handlers/HandleBuilder.java | 6 +- .../eclipse/handlers/HandleSuperBuilder.java | 4 +- .../singulars/EclipseGuavaSingularizer.java | 10 +- .../EclipseJavaUtilListSetSingularizer.java | 10 +- .../singulars/EclipseJavaUtilMapSingularizer.java | 6 +- src/core/lombok/experimental/Accessors.java | 9 -- src/core/lombok/javac/handlers/HandleBuilder.java | 4 +- .../lombok/javac/handlers/HandleSuperBuilder.java | 4 +- .../javac/handlers/JavacSingularsRecipes.java | 6 +- .../BuilderWithJavaBeansSpecCapitalization.java | 106 +++++++++++++++++++++ .../GetterWithJavaBeansSpecCapitalization.java | 18 +--- .../SetterWithJavaBeansSpecCapitalization.java | 15 --- .../ValueWithJavaBeansSpecCapitalization.java | 11 --- .../WithOnJavaBeansSpecCapitalization.java | 29 ------ .../WithWithJavaBeansSpecCapitalization.java | 12 +++ .../BuilderWithJavaBeansSpecCapitalization.java | 99 +++++++++++++++++++ .../GetterWithJavaBeansSpecCapitalization.java | 24 +---- .../SetterWithJavaBeansSpecCapitalization.java | 24 +---- .../ValueWithJavaBeansSpecCapitalization.java | 31 +----- .../WithOnJavaBeansSpecCapitalization.java | 25 ----- .../WithWithJavaBeansSpecCapitalization.java | 12 +++ .../BuilderWithJavaBeansSpecCapitalization.java | 7 ++ .../GetterWithJavaBeansSpecCapitalization.java | 8 +- .../SetterWithJavaBeansSpecCapitalization.java | 8 +- .../ValueWithJavaBeansSpecCapitalization.java | 7 +- .../before/WithOnJavaBeansSpecCapitalization.java | 16 ---- .../WithWithJavaBeansSpecCapitalization.java | 8 ++ 32 files changed, 382 insertions(+), 279 deletions(-) create mode 100644 src/core/lombok/core/configuration/CapitalizationStrategy.java create mode 100644 test/transform/resource/after-delombok/BuilderWithJavaBeansSpecCapitalization.java delete mode 100644 test/transform/resource/after-delombok/WithOnJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/after-delombok/WithWithJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/after-ecj/BuilderWithJavaBeansSpecCapitalization.java delete mode 100644 test/transform/resource/after-ecj/WithOnJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/after-ecj/WithWithJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/before/BuilderWithJavaBeansSpecCapitalization.java delete mode 100644 test/transform/resource/before/WithOnJavaBeansSpecCapitalization.java create mode 100644 test/transform/resource/before/WithWithJavaBeansSpecCapitalization.java diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 12307471..05550a06 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2020 The Project Lombok Authors. + * Copyright (C) 2013-2021 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 @@ -24,6 +24,7 @@ package lombok; import java.util.List; import lombok.core.configuration.CallSuperType; +import lombok.core.configuration.CapitalizationStrategy; import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.configuration.ConfigurationKey; import lombok.core.configuration.FlagUsageType; @@ -559,11 +560,12 @@ public class ConfigurationKeys { public static final ConfigurationKey ACCESSORS_FLUENT = new ConfigurationKey("lombok.accessors.fluent", "Generate getters and setters using only the field name (no get/set prefix) (default: false).") {}; /** - * lombok configuration: {@code lombok.accessors.javaBeansSpecCapitalization} = {@code true} | {@code false}. + * lombok configuration: {@code lombok.accessors.capitalization} = {@code basic} | {@code beanspec}. * - * For any class without an {@code @Accessors} that explicitly defines the {@code javaBeansSpecCapitalization} option, this value is used (default = false). + * Which capitalization rule is used to turn field names into getter/setter/with names and vice versa for field names that start with 1 lowercase letter, then 1 uppercase letter. + * basic = {@code uShape} becomes {@code getUShape}, beanspec = {@code uShape} becomes {@code getuShape} (default = basic). */ - public static final ConfigurationKey ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION = new ConfigurationKey("lombok.accessors.javaBeansSpecCapitalization", "Generating accessors name according to the JavaBeans Spec (default: false).") {}; + public static final ConfigurationKey ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION = new ConfigurationKey("lombok.accessors.capitalization", "Which capitalization strategy to use when converting field names to accessor names and vice versa (default: basic).") {}; // ----- ExtensionMethod ----- diff --git a/src/core/lombok/core/AST.java b/src/core/lombok/core/AST.java index 9f3a471f..07d035c5 100755 --- a/src/core/lombok/core/AST.java +++ b/src/core/lombok/core/AST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2019 The Project Lombok Authors. + * Copyright (C) 2009-2021 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 @@ -430,6 +430,9 @@ public abstract class AST, L extends LombokNode, } } + /** + * @return The {@code lombok.config} configuration value for the provided {@code key}, or {@code null} if that key is not in the config / there is no config. + */ public final T readConfiguration(ConfigurationKey key) { long start = configTracker == null ? 0L : configTracker.start(); try { @@ -438,4 +441,17 @@ public abstract class AST, L extends LombokNode, if (configTracker != null) configTracker.end(start); } } + + /** + * @return The {@code lombok.config} configuration value for the provided {@code key}, or {@code defaultValue} if that key is not in the config / there is no config. + */ + public final T readConfigurationOr(ConfigurationKey key, T defaultValue) { + long start = configTracker == null ? 0L : configTracker.start(); + try { + T value = LombokConfiguration.read(key, this); + return value != null ? value : defaultValue; + } finally { + if (configTracker != null) configTracker.end(start); + } + } } diff --git a/src/core/lombok/core/configuration/CapitalizationStrategy.java b/src/core/lombok/core/configuration/CapitalizationStrategy.java new file mode 100644 index 00000000..affd3576 --- /dev/null +++ b/src/core/lombok/core/configuration/CapitalizationStrategy.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 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.core.configuration; + +/** Used for lombok configuration to determine how to transform field names when turning them into accessor method names and vice versa. */ +public enum CapitalizationStrategy { + BASIC { + @Override public String capitalize(String in) { + if (in.length() == 0) return in; + char first = in.charAt(0); + if (!Character.isLowerCase(first)) return in; + boolean useUpperCase = in.length() > 2 && + (Character.isTitleCase(in.charAt(1)) || Character.isUpperCase(in.charAt(1))); + return (useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first)) + in.substring(1); + } + }, + BEANSPEC { + @Override public String capitalize(String in) { + if (in.length() == 0) return in; + char first = in.charAt(0); + if (!Character.isLowerCase(first) || (in.length() > 1 && Character.isUpperCase(in.charAt(1)))) return in; + boolean useUpperCase = in.length() > 2 && Character.isTitleCase(in.charAt(1)); + return (useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first)) + in.substring(1); + } + }, + ; + + public static CapitalizationStrategy defaultValue() { + return BASIC; + } + + public abstract String capitalize(String in); +} diff --git a/src/core/lombok/core/configuration/FlagUsageType.java b/src/core/lombok/core/configuration/FlagUsageType.java index 8717c22b..293a2f1d 100644 --- a/src/core/lombok/core/configuration/FlagUsageType.java +++ b/src/core/lombok/core/configuration/FlagUsageType.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Project Lombok Authors. + * Copyright (C) 2014-2021 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 @@ -21,7 +21,7 @@ */ package lombok.core.configuration; -/** Used for lombok configuration to flag usages of certain lombok feature. */ +/** Used for lombok configuration to flag usages of certain lombok features. */ public enum FlagUsageType { WARNING, ERROR, ALLOW; } diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index f45481d4..c00b5dca 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2020 The Project Lombok Authors. + * Copyright (C) 2013-2021 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 @@ -46,6 +46,7 @@ import lombok.core.AnnotationValues; import lombok.core.JavaIdentifiers; import lombok.core.LombokNode; import lombok.core.configuration.AllowHelper; +import lombok.core.configuration.CapitalizationStrategy; import lombok.core.configuration.ConfigurationKey; import lombok.core.configuration.FlagUsageType; import lombok.experimental.Accessors; @@ -591,7 +592,7 @@ public class HandlerUtil { List prefix = explicitPrefix ? Arrays.asList(ac.prefix()) : ast.readConfiguration(ConfigurationKeys.ACCESSORS_PREFIX); boolean fluent = explicitFluent ? ac.fluent() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT)); - boolean javaBeansSpecCapitalization = explicitJavaBeansSpecCapitalization ? ac.javaBeansSpecCapitalization() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION)); + CapitalizationStrategy capitalizationStrategy = ast.readConfigurationOr(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION, CapitalizationStrategy.defaultValue()); fieldName = removePrefix(fieldName, prefix); if (fieldName == null) return null; @@ -604,7 +605,7 @@ public class HandlerUtil { return booleanPrefix + fName.substring(2); } - return buildAccessorName(isBoolean ? booleanPrefix : normalPrefix, fName, javaBeansSpecCapitalization); + return buildAccessorName(isBoolean ? booleanPrefix : normalPrefix, fName, capitalizationStrategy); } /** @@ -677,14 +678,13 @@ public class HandlerUtil { boolean explicitPrefix = accessors != null && accessors.isExplicit("prefix"); boolean explicitFluent = accessors != null && accessors.isExplicit("fluent"); - boolean explicitJavaBeansSpecCapitalization = accessors != null && accessors.isExplicit("javaBeansSpecCapitalization"); - Accessors ac = (explicitPrefix || explicitFluent || explicitJavaBeansSpecCapitalization) ? accessors.getInstance() : null; + Accessors ac = (explicitPrefix || explicitFluent) ? accessors.getInstance() : null; List prefix = explicitPrefix ? Arrays.asList(ac.prefix()) : ast.readConfiguration(ConfigurationKeys.ACCESSORS_PREFIX); boolean fluent = explicitFluent ? ac.fluent() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT)); - boolean javaBeansSpecCapitalization = explicitJavaBeansSpecCapitalization ? ac.javaBeansSpecCapitalization() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION)); - + CapitalizationStrategy capitalizationStrategy = ast.readConfigurationOr(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION, CapitalizationStrategy.defaultValue()); + fieldName = removePrefix(fieldName, prefix); if (fieldName == null) return Collections.emptyList(); @@ -695,8 +695,8 @@ public class HandlerUtil { if (adhereToFluent && fluent) { names.add(baseName); } else { - names.add(buildAccessorName(normalPrefix, baseName, javaBeansSpecCapitalization)); - if (!normalPrefix.equals(booleanPrefix)) names.add(buildAccessorName(booleanPrefix, baseName, javaBeansSpecCapitalization)); + names.add(buildAccessorName(normalPrefix, baseName, capitalizationStrategy)); + if (!normalPrefix.equals(booleanPrefix)) names.add(buildAccessorName(booleanPrefix, baseName, capitalizationStrategy)); } } @@ -722,40 +722,36 @@ public class HandlerUtil { } /** + * @param node Any node (used to fetch config of capitalization strategy). + * @param prefix Something like {@code get} or {@code set} or {@code is}. + * @param suffix Something like {@code running}. + * @return prefix + smartly title-cased suffix. For example, {@code setRunning}. + */ + public static String buildAccessorName(AST ast, String prefix, String suffix) { + CapitalizationStrategy capitalizationStrategy = ast.readConfigurationOr(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION, CapitalizationStrategy.defaultValue()); + return buildAccessorName(prefix, suffix, capitalizationStrategy); + } + + /** + * @param node Any node (used to fetch config of capitalization strategy). * @param prefix Something like {@code get} or {@code set} or {@code is}. * @param suffix Something like {@code running}. * @return prefix + smartly title-cased suffix. For example, {@code setRunning}. */ - public static String buildAccessorName(String prefix, String suffix) { - return buildAccessorName(prefix, suffix, false); + public static String buildAccessorName(LombokNode node, String prefix, String suffix) { + CapitalizationStrategy capitalizationStrategy = node.getAst().readConfigurationOr(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION, CapitalizationStrategy.defaultValue()); + return buildAccessorName(prefix, suffix, capitalizationStrategy); } /** * @param prefix Something like {@code get} or {@code set} or {@code is}. * @param suffix Something like {@code running}. - * @param shouldFollowJavaBeansSpecCapitalization {@code boolean} that indicates whether the capitalization rules should follow JavaBeanSpec - * @return if shouldFollowJavaBeansSpecCapitalization is {@code true} and name start with only single lowercase letter, returns simple suffix+prefix. For example, {@code setaFieldName} - * otherwise, returns prefix + smartly title-cased suffix. For example, {@code setRunning}. + * @param capitalizationStrategy Which strategy to use to capitalize the name part. */ - private static String buildAccessorName(String prefix, String suffix, boolean shouldFollowJavaBeansSpecCapitalization) { + private static String buildAccessorName(String prefix, String suffix, CapitalizationStrategy capitalizationStrategy) { if (suffix.length() == 0) return prefix; if (prefix.length() == 0) return suffix; - - char first = suffix.charAt(0); - if (!Character.isLowerCase(first)) { - return String.format("%s%s", prefix, suffix); - } - - boolean useUpperCase = suffix.length() > 2 && - (Character.isTitleCase(suffix.charAt(1)) || Character.isUpperCase(suffix.charAt(1))); - if (shouldFollowJavaBeansSpecCapitalization && useUpperCase) { - return String.format("%s%s", prefix, suffix); - } - - suffix = String.format("%s%s", - useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first), - suffix.subSequence(1, suffix.length())); - return String.format("%s%s", prefix, suffix); + return prefix + capitalizationStrategy.capitalize(suffix); } public static String camelCaseToConstant(String fieldName) { diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 82d3bfcf..2bfe1e8b 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -665,7 +665,7 @@ public class HandleBuilder extends EclipseAnnotationHandler { for (BuilderFieldData bfd : job.builderFields) { String setterName = new String(bfd.name); String setterPrefix = !prefix.isEmpty() ? prefix : job.oldFluent ? "" : "set"; - if (!setterPrefix.isEmpty()) setterName = HandlerUtil.buildAccessorName(setterPrefix, setterName); + if (!setterPrefix.isEmpty()) setterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, setterName); MessageSend ms = new MessageSend(); Expression[] tgt = new Expression[bfd.singularData == null ? 1 : 2]; @@ -1033,9 +1033,9 @@ public class HandleBuilder extends EclipseAnnotationHandler { String setterPrefix = prefix.isEmpty() ? "set" : prefix; String setterName; if (job.oldFluent) { - setterName = prefix.isEmpty() ? new String(bfd.name) : HandlerUtil.buildAccessorName(setterPrefix, new String(bfd.name)); + setterName = prefix.isEmpty() ? new String(bfd.name) : HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, new String(bfd.name)); } else { - setterName = HandlerUtil.buildAccessorName(setterPrefix, new String(bfd.name)); + setterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, new String(bfd.name)); } for (int i = 0; i < len; i++) { diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 5bc6c125..26b62cbf 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -798,7 +798,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { } private MessageSend createSetterCallWithInstanceValue(BuilderFieldData bfd, EclipseNode type, ASTNode source, String setterPrefix) { - char[] setterName = HandlerUtil.buildAccessorName(setterPrefix, String.valueOf(bfd.name)).toCharArray(); + char[] setterName = HandlerUtil.buildAccessorName(type, setterPrefix, String.valueOf(bfd.name)).toCharArray(); MessageSend ms = new MessageSend(); Expression[] tgt = new Expression[bfd.singularData == null ? 1 : 2]; @@ -1004,7 +1004,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { if (existing == null) existing = EMPTY_METHODS; int len = existing.length; - String setterName = HandlerUtil.buildAccessorName(setterPrefix, new String(paramName)); + String setterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, new String(paramName)); for (int i = 0; i < len; i++) { if (!(existing[i] instanceof MethodDeclaration)) continue; diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java index 7dcf18c9..9b464a25 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java @@ -126,7 +126,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L); thisDotField.receiver = new ThisReference(0, 0); Assignment a = new Assignment(thisDotField, new NullLiteral(0, 0), 0); - md.selector = HandlerUtil.buildAccessorName("clear", new String(data.getPluralName())).toCharArray(); + md.selector = HandlerUtil.buildAccessorName(builderType, "clear", new String(data.getPluralName())).toCharArray(); md.statements = returnStatement != null ? new Statement[] {a, returnStatement} : new Statement[] {a}; md.returnType = returnType; md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); @@ -173,8 +173,8 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { md.arguments[i].annotations = typeUseAnns; } md.returnType = returnType; - char[] prefixedSingularName = data.getSetterPrefix().length == 0 ? data.getSingularName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getSingularName())).toCharArray(); - md.selector = fluent ? prefixedSingularName : HandlerUtil.buildAccessorName("add", new String(data.getSingularName())).toCharArray(); + char[] prefixedSingularName = data.getSetterPrefix().length == 0 ? data.getSingularName() : HandlerUtil.buildAccessorName(builderType, new String(data.getSetterPrefix()), new String(data.getSingularName())).toCharArray(); + md.selector = fluent ? prefixedSingularName : HandlerUtil.buildAccessorName(builderType, "add", new String(data.getSingularName())).toCharArray(); Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToBuilderSingularSetterAnnotations(data.getAnnotation().up())); md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); @@ -213,8 +213,8 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { md.arguments = new Argument[] {param}; md.returnType = returnType; - char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray(); - md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName("addAll", new String(data.getPluralName())).toCharArray(); + char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(builderType, new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray(); + md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName(builderType, "addAll", new String(data.getPluralName())).toCharArray(); Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up())); md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java index 882b7adc..6f5e9add 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java @@ -112,7 +112,7 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula thisDotField.receiver = new ThisReference(0, 0); FieldReference thisDotField2 = new FieldReference(data.getPluralName(), 0L); thisDotField2.receiver = new ThisReference(0, 0); - md.selector = HandlerUtil.buildAccessorName("clear", new String(data.getPluralName())).toCharArray(); + md.selector = HandlerUtil.buildAccessorName(builderType, "clear", new String(data.getPluralName())).toCharArray(); MessageSend clearMsg = new MessageSend(); clearMsg.receiver = thisDotField2; clearMsg.selector = "clear".toCharArray(); @@ -151,8 +151,8 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula param.annotations = typeUseAnns; md.arguments = new Argument[] {param}; md.returnType = returnType; - char[] prefixedSingularName = data.getSetterPrefix().length == 0 ? data.getSingularName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getSingularName())).toCharArray(); - md.selector = fluent ? prefixedSingularName : HandlerUtil.buildAccessorName("add", new String(data.getSingularName())).toCharArray(); + char[] prefixedSingularName = data.getSetterPrefix().length == 0 ? data.getSingularName() : HandlerUtil.buildAccessorName(builderType, new String(data.getSetterPrefix()), new String(data.getSingularName())).toCharArray(); + md.selector = fluent ? prefixedSingularName : HandlerUtil.buildAccessorName(builderType, "add", new String(data.getSingularName())).toCharArray(); Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToBuilderSingularSetterAnnotations(data.getAnnotation().up())); md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); @@ -189,8 +189,8 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula md.arguments = new Argument[] {param}; md.returnType = returnType; - char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray(); - md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName("addAll", new String(data.getPluralName())).toCharArray(); + char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(builderType, new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray(); + md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName(builderType, "addAll", new String(data.getPluralName())).toCharArray(); Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up())); md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java index a766612f..c28ba59d 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java @@ -177,7 +177,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer thisDotField2.receiver = new ThisReference(0, 0); FieldReference thisDotField3 = new FieldReference(valueFieldName, 0L); thisDotField3.receiver = new ThisReference(0, 0); - md.selector = HandlerUtil.buildAccessorName("clear", new String(data.getPluralName())).toCharArray(); + md.selector = HandlerUtil.buildAccessorName(builderType, "clear", new String(data.getPluralName())).toCharArray(); MessageSend clearMsg1 = new MessageSend(); clearMsg1.receiver = thisDotField2; clearMsg1.selector = "clear".toCharArray(); @@ -249,7 +249,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer String name = new String(data.getSingularName()); String setterPrefix = data.getSetterPrefix().length > 0 ? new String(data.getSetterPrefix()) : fluent ? "" : "put"; - String setterName = HandlerUtil.buildAccessorName(setterPrefix, name); + String setterName = HandlerUtil.buildAccessorName(builderType, setterPrefix, name); md.selector = setterName.toCharArray(); Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); @@ -325,7 +325,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer String name = new String(data.getPluralName()); String setterPrefix = data.getSetterPrefix().length > 0 ? new String(data.getSetterPrefix()) : fluent ? "" : "put"; - String setterName = HandlerUtil.buildAccessorName(setterPrefix, name); + String setterName = HandlerUtil.buildAccessorName(builderType, setterPrefix, name); md.selector = setterName.toCharArray(); Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); diff --git a/src/core/lombok/experimental/Accessors.java b/src/core/lombok/experimental/Accessors.java index b3da9a5b..dc9ae4b0 100644 --- a/src/core/lombok/experimental/Accessors.java +++ b/src/core/lombok/experimental/Accessors.java @@ -54,15 +54,6 @@ public @interface Accessors { */ boolean chain() default false; - /** - * If true, accessors names will be capitalized according to JavaBeans capitalization rules. - * If {@code true}, an accessor for a field that starts with a single lowercase letter followed by a capital letter, - * wont capitalize the first letter (named {@code getaFieldName()}, not for example {@code getAFieldName}). - * default: false - * @return - */ - boolean javaBeansSpecCapitalization() default false; - /** * If present, only fields with any of the stated prefixes are given the getter/setter treatment. * Note that a prefix only counts if the next character is NOT a lowercase character or the last diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index bb852b55..d8fdfb1b 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -636,7 +636,7 @@ public class HandleBuilder extends JavacAnnotationHandler { for (BuilderFieldData bfd : job.builderFields) { String setterPrefix = !prefix.isEmpty() ? prefix : job.oldFluent ? "" : "set"; String prefixedSetterName = bfd.name.toString(); - if (!setterPrefix.isEmpty()) prefixedSetterName = HandlerUtil.buildAccessorName(setterPrefix, prefixedSetterName); + if (!setterPrefix.isEmpty()) prefixedSetterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, prefixedSetterName); Name setterName = job.toName(prefixedSetterName); JCExpression[] tgt = new JCExpression[bfd.singularData == null ? 1 : 2]; @@ -901,7 +901,7 @@ public class HandleBuilder extends JavacAnnotationHandler { private void makePrefixedSetterMethodForBuilder(BuilderJob job, BuilderFieldData bfd, boolean deprecate, String prefix) { JavacNode fieldNode = bfd.createdFields.get(0); String setterPrefix = !prefix.isEmpty() ? prefix : job.oldFluent ? "" : "set"; - String setterName = HandlerUtil.buildAccessorName(setterPrefix, bfd.name.toString()); + String setterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, bfd.name.toString()); Name setterName_ = job.builderType.toName(setterName); for (JavacNode child : job.builderType.down()) { diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index 50193f99..b5bc73fb 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -777,7 +777,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { arg = maker.Conditional(eqNull, emptyCollection, tgt[1]); } - String setterName = HandlerUtil.buildAccessorName(setterPrefix, bfd.name.toString()); + String setterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, bfd.name.toString()); JCMethodInvocation apply = maker.Apply(List.nil(), maker.Select(maker.Ident(job.toName(BUILDER_VARIABLE_NAME)), job.toName(setterName)), List.of(arg)); JCExpressionStatement exec = maker.Exec(apply); return exec; @@ -949,7 +949,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } private void generateSimpleSetterMethodForBuilder(SuperBuilderJob job, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JCExpression returnType, JCStatement returnStatement, List annosOnParam, JavacNode originalFieldNode, String setterPrefix) { - String setterName = HandlerUtil.buildAccessorName(setterPrefix, paramName.toString()); + String setterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, paramName.toString()); Name setterName_ = job.builderType.toName(setterName); for (JavacNode child : job.builderType.down()) { diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index 4ca09b82..77fcd4ea 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -300,7 +300,7 @@ public class JavacSingularsRecipes { ListBuffer statements = new ListBuffer(); statements.append(clearStatement); - Name methodName = builderType.toName(HandlerUtil.buildAccessorName("clear", data.getPluralName().toString())); + Name methodName = builderType.toName(HandlerUtil.buildAccessorName(source, "clear", data.getPluralName().toString())); finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, methodName, List.nil(), List.nil(), access, null); } @@ -312,7 +312,7 @@ public class JavacSingularsRecipes { Name name = data.getSingularName(); String setterPrefix = data.getSetterPrefix(); if (setterPrefix.isEmpty() && !fluent) setterPrefix = getAddMethodName(); - if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(setterPrefix, name.toString())); + if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(source, setterPrefix, name.toString())); statements.prepend(createConstructBuilderVarIfNeeded(maker, data, builderType, source)); List methodAnnotations = copyAnnotations(findCopyableToBuilderSingularSetterAnnotations(data.annotation.up())); @@ -344,7 +344,7 @@ public class JavacSingularsRecipes { Name name = data.getPluralName(); String setterPrefix = data.getSetterPrefix(); if (setterPrefix.isEmpty() && !fluent) setterPrefix = getAddMethodName() + "All"; - if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(setterPrefix, name.toString())); + if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(source, setterPrefix, name.toString())); JCExpression paramType = getPluralMethodParamType(builderType); paramType = addTypeArgs(getTypeArgumentsCount(), true, builderType, paramType, data.getTypeArgs(), source); long paramFlags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext()); diff --git a/test/transform/resource/after-delombok/BuilderWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/BuilderWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..4a21f2c3 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderWithJavaBeansSpecCapitalization.java @@ -0,0 +1,106 @@ +class BuilderWithJavaBeansSpecCapitalization { + java.util.List a; + java.util.List aField; + String bField; + @java.lang.SuppressWarnings("all") + BuilderWithJavaBeansSpecCapitalization(final java.util.List a, final java.util.List aField, final String bField) { + this.a = a; + this.aField = aField; + this.bField = bField; + } + @java.lang.SuppressWarnings("all") + public static class BuilderWithJavaBeansSpecCapitalizationBuilder { + @java.lang.SuppressWarnings("all") + private java.util.ArrayList a; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList aField; + @java.lang.SuppressWarnings("all") + private String bField; + @java.lang.SuppressWarnings("all") + BuilderWithJavaBeansSpecCapitalizationBuilder() { + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setZ(final String z) { + if (this.a == null) this.a = new java.util.ArrayList(); + this.a.add(z); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setA(final java.util.Collection a) { + if (a == null) { + throw new java.lang.NullPointerException("a cannot be null"); + } + if (this.a == null) this.a = new java.util.ArrayList(); + this.a.addAll(a); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder clearA() { + if (this.a != null) this.a.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setyField(final String yField) { + if (this.aField == null) this.aField = new java.util.ArrayList(); + this.aField.add(yField); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setaField(final java.util.Collection aField) { + if (aField == null) { + throw new java.lang.NullPointerException("aField cannot be null"); + } + if (this.aField == null) this.aField = new java.util.ArrayList(); + this.aField.addAll(aField); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder clearaField() { + if (this.aField != null) this.aField.clear(); + return this; + } + /** + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setbField(final String bField) { + this.bField = bField; + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization build() { + java.util.List a; + switch (this.a == null ? 0 : this.a.size()) { + case 0: + a = java.util.Collections.emptyList(); + break; + case 1: + a = java.util.Collections.singletonList(this.a.get(0)); + break; + default: + a = java.util.Collections.unmodifiableList(new java.util.ArrayList(this.a)); + } + java.util.List aField; + switch (this.aField == null ? 0 : this.aField.size()) { + case 0: + aField = java.util.Collections.emptyList(); + break; + case 1: + aField = java.util.Collections.singletonList(this.aField.get(0)); + break; + default: + aField = java.util.Collections.unmodifiableList(new java.util.ArrayList(this.aField)); + } + return new BuilderWithJavaBeansSpecCapitalization(a, aField, this.bField); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder(a=" + this.a + ", aField=" + this.aField + ", bField=" + this.bField + ")"; + } + } + @java.lang.SuppressWarnings("all") + public static BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder builder() { + return new BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java index 06026c1b..51ccfe63 100644 --- a/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java +++ b/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java @@ -1,17 +1,3 @@ -class GetterWithoutJavaBeansSpecCapitalization { - int a; - int aField; - @java.lang.SuppressWarnings("all") - public int getA() { - return this.a; - } - @java.lang.SuppressWarnings("all") - public int getAField() { - return this.aField; - } -} - - class GetterWithJavaBeansSpecCapitalization { int a; int aField; @@ -23,6 +9,4 @@ class GetterWithJavaBeansSpecCapitalization { public int getaField() { return this.aField; } -} - - +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java index 24c8e883..de68ee60 100644 --- a/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java +++ b/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java @@ -1,16 +1,3 @@ -class SetterWithoutJavaBeansSpecCapitalization { - int a; - int aField; - @java.lang.SuppressWarnings("all") - public void setA(final int a) { - this.a = a; - } - @java.lang.SuppressWarnings("all") - public void setAField(final int aField) { - this.aField = aField; - } -} - class SetterWithJavaBeansSpecCapitalization { int a; int aField; @@ -23,5 +10,3 @@ class SetterWithJavaBeansSpecCapitalization { this.aField = aField; } } - - diff --git a/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java index 20139baf..b92dd5b6 100644 --- a/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java +++ b/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java @@ -1,16 +1,13 @@ final class ValueWithJavaBeansSpecCapitalization { private final int aField; - @java.lang.SuppressWarnings("all") public ValueWithJavaBeansSpecCapitalization(final int aField) { this.aField = aField; } - @java.lang.SuppressWarnings("all") public int getaField() { return this.aField; } - @java.lang.Override @java.lang.SuppressWarnings("all") public boolean equals(final java.lang.Object o) { @@ -20,7 +17,6 @@ final class ValueWithJavaBeansSpecCapitalization { if (this.getaField() != other.getaField()) return false; return true; } - @java.lang.Override @java.lang.SuppressWarnings("all") public int hashCode() { @@ -29,27 +25,22 @@ final class ValueWithJavaBeansSpecCapitalization { result = result * PRIME + this.getaField(); return result; } - @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { return "ValueWithJavaBeansSpecCapitalization(aField=" + this.getaField() + ")"; } } - final class ValueWithoutJavaBeansSpecCapitalization { private final int aField; - @java.lang.SuppressWarnings("all") public ValueWithoutJavaBeansSpecCapitalization(final int aField) { this.aField = aField; } - @java.lang.SuppressWarnings("all") public int getAField() { return this.aField; } - @java.lang.Override @java.lang.SuppressWarnings("all") public boolean equals(final java.lang.Object o) { @@ -59,7 +50,6 @@ final class ValueWithoutJavaBeansSpecCapitalization { if (this.getAField() != other.getAField()) return false; return true; } - @java.lang.Override @java.lang.SuppressWarnings("all") public int hashCode() { @@ -68,7 +58,6 @@ final class ValueWithoutJavaBeansSpecCapitalization { result = result * PRIME + this.getAField(); return result; } - @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { diff --git a/test/transform/resource/after-delombok/WithOnJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/WithOnJavaBeansSpecCapitalization.java deleted file mode 100644 index afed2f0e..00000000 --- a/test/transform/resource/after-delombok/WithOnJavaBeansSpecCapitalization.java +++ /dev/null @@ -1,29 +0,0 @@ -class WithOnJavaBeansSpecCapitalization { - int aField; - - WithOnJavaBeansSpecCapitalization(int aField) { - } - - /** - * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). - */ - @java.lang.SuppressWarnings("all") - public WithOnJavaBeansSpecCapitalization withaField(final int aField) { - return this.aField == aField ? this : new WithOnJavaBeansSpecCapitalization(aField); - } -} - -class WithOffJavaBeansSpecCapitalization { - int aField; - - WithOffJavaBeansSpecCapitalization(int aField) { - } - - /** - * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). - */ - @java.lang.SuppressWarnings("all") - public WithOffJavaBeansSpecCapitalization withAField(final int aField) { - return this.aField == aField ? this : new WithOffJavaBeansSpecCapitalization(aField); - } -} diff --git a/test/transform/resource/after-delombok/WithWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/WithWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..e3737848 --- /dev/null +++ b/test/transform/resource/after-delombok/WithWithJavaBeansSpecCapitalization.java @@ -0,0 +1,12 @@ +class WithWithJavaBeansSpecCapitalization { + int aField; + WithWithJavaBeansSpecCapitalization(int aField) { + } + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + @java.lang.SuppressWarnings("all") + public WithWithJavaBeansSpecCapitalization withaField(final int aField) { + return this.aField == aField ? this : new WithWithJavaBeansSpecCapitalization(aField); + } +} diff --git a/test/transform/resource/after-ecj/BuilderWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/BuilderWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..1107254f --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderWithJavaBeansSpecCapitalization.java @@ -0,0 +1,99 @@ +@lombok.Builder(setterPrefix = "set") class BuilderWithJavaBeansSpecCapitalization { + public static @java.lang.SuppressWarnings("all") class BuilderWithJavaBeansSpecCapitalizationBuilder { + private @java.lang.SuppressWarnings("all") java.util.ArrayList a; + private @java.lang.SuppressWarnings("all") java.util.ArrayList aField; + private @java.lang.SuppressWarnings("all") String bField; + @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalizationBuilder() { + super(); + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setZ(final String z) { + if ((this.a == null)) + this.a = new java.util.ArrayList(); + this.a.add(z); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setA(final java.util.Collection a) { + if ((a == null)) + { + throw new java.lang.NullPointerException("a cannot be null"); + } + if ((this.a == null)) + this.a = new java.util.ArrayList(); + this.a.addAll(a); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder clearA() { + if ((this.a != null)) + this.a.clear(); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setyField(final String yField) { + if ((this.aField == null)) + this.aField = new java.util.ArrayList(); + this.aField.add(yField); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setaField(final java.util.Collection aField) { + if ((aField == null)) + { + throw new java.lang.NullPointerException("aField cannot be null"); + } + if ((this.aField == null)) + this.aField = new java.util.ArrayList(); + this.aField.addAll(aField); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder clearaField() { + if ((this.aField != null)) + this.aField.clear(); + return this; + } + /** + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setbField(final String bField) { + this.bField = bField; + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization build() { + java.util.List a; + switch (((this.a == null) ? 0 : this.a.size())) { + case 0 : + a = java.util.Collections.emptyList(); + break; + case 1 : + a = java.util.Collections.singletonList(this.a.get(0)); + break; + default : + a = java.util.Collections.unmodifiableList(new java.util.ArrayList(this.a)); + } + java.util.List aField; + switch (((this.aField == null) ? 0 : this.aField.size())) { + case 0 : + aField = java.util.Collections.emptyList(); + break; + case 1 : + aField = java.util.Collections.singletonList(this.aField.get(0)); + break; + default : + aField = java.util.Collections.unmodifiableList(new java.util.ArrayList(this.aField)); + } + return new BuilderWithJavaBeansSpecCapitalization(a, aField, this.bField); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((((("BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder(a=" + this.a) + ", aField=") + this.aField) + ", bField=") + this.bField) + ")"); + } + } + @lombok.Singular("z") java.util.List a; + @lombok.Singular("yField") java.util.List aField; + String bField; + @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization(final java.util.List a, final java.util.List aField, final String bField) { + super(); + this.a = a; + this.aField = aField; + this.bField = bField; + } + public static @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder builder() { + return new BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder(); + } +} diff --git a/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java index d605b4ac..745529a0 100644 --- a/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java +++ b/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java @@ -1,33 +1,13 @@ -class GetterWithoutJavaBeansSpecCapitalization { +class GetterWithJavaBeansSpecCapitalization { @lombok.Getter int a; @lombok.Getter int aField; - - GetterWithoutJavaBeansSpecCapitalization() { - super(); - } - - public @java.lang.SuppressWarnings("all") int getA() { - return this.a; - } - - public @java.lang.SuppressWarnings("all") int getAField() { - return this.aField; - } -} - -@lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class GetterWithJavaBeansSpecCapitalization { - @lombok.Getter int a; - @lombok.Getter int aField; - GetterWithJavaBeansSpecCapitalization() { super(); } - public @java.lang.SuppressWarnings("all") int getA() { return this.a; } - public @java.lang.SuppressWarnings("all") int getaField() { return this.aField; } -} +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java index 9907621f..4e99890a 100644 --- a/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java +++ b/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java @@ -1,33 +1,13 @@ -class SetterWithoutJavaBeansSpecCapitalization { +class SetterWithJavaBeansSpecCapitalization { @lombok.Setter int a; @lombok.Setter int aField; - - SetterWithoutJavaBeansSpecCapitalization() { - super(); - } - - public @java.lang.SuppressWarnings("all") void setA(final int a) { - this.a = a; - } - - public @java.lang.SuppressWarnings("all") void setAField(final int aField) { - this.aField = aField; - } -} - -@lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class SetterWithJavaBeansSpecCapitalization { - @lombok.Setter int a; - @lombok.Setter int aField; - SetterWithJavaBeansSpecCapitalization() { super(); } - public @java.lang.SuppressWarnings("all") void setA(final int a) { this.a = a; } - public @java.lang.SuppressWarnings("all") void setaField(final int aField) { this.aField = aField; } -} +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java index f41fcf58..8117dbb0 100644 --- a/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java +++ b/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java @@ -1,4 +1,4 @@ -final @lombok.Value @lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class ValueWithJavaBeansSpecCapitalization { +final @lombok.Value class ValueWithJavaBeansSpecCapitalization { private final int aField; public @java.lang.SuppressWarnings("all") int getaField() { return this.aField; @@ -27,32 +27,3 @@ final @lombok.Value @lombok.experimental.Accessors(javaBeansSpecCapitalization = this.aField = aField; } } -final @lombok.Value class ValueWithoutJavaBeansSpecCapitalization { - private final int aField; - public @java.lang.SuppressWarnings("all") int getAField() { - return this.aField; - } - public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { - if ((o == this)) - return true; - if ((! (o instanceof ValueWithoutJavaBeansSpecCapitalization))) - return false; - final ValueWithoutJavaBeansSpecCapitalization other = (ValueWithoutJavaBeansSpecCapitalization) o; - if ((this.getAField() != other.getAField())) - return false; - return true; - } - public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { - final int PRIME = 59; - int result = 1; - result = ((result * PRIME) + this.getAField()); - return result; - } - public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { - return (("ValueWithoutJavaBeansSpecCapitalization(aField=" + this.getAField()) + ")"); - } - public @java.lang.SuppressWarnings("all") ValueWithoutJavaBeansSpecCapitalization(final int aField) { - super(); - this.aField = aField; - } -} diff --git a/test/transform/resource/after-ecj/WithOnJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/WithOnJavaBeansSpecCapitalization.java deleted file mode 100644 index 06164fe9..00000000 --- a/test/transform/resource/after-ecj/WithOnJavaBeansSpecCapitalization.java +++ /dev/null @@ -1,25 +0,0 @@ -@lombok.With @lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class WithOnJavaBeansSpecCapitalization { - int aField; - WithOnJavaBeansSpecCapitalization(int aField) { - super(); - } - /** - * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). - */ - public @java.lang.SuppressWarnings("all") WithOnJavaBeansSpecCapitalization withaField(final int aField) { - return ((this.aField == aField) ? this : new WithOnJavaBeansSpecCapitalization(aField)); - } -} - -@lombok.With class WithOffJavaBeansSpecCapitalization { - int aField; - WithOffJavaBeansSpecCapitalization(int aField) { - super(); - } - /** - * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). - */ - public @java.lang.SuppressWarnings("all") WithOffJavaBeansSpecCapitalization withAField(final int aField) { - return ((this.aField == aField) ? this : new WithOffJavaBeansSpecCapitalization(aField)); - } -} diff --git a/test/transform/resource/after-ecj/WithWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/WithWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..d530ad8a --- /dev/null +++ b/test/transform/resource/after-ecj/WithWithJavaBeansSpecCapitalization.java @@ -0,0 +1,12 @@ +@lombok.With class WithOnJavaBeansSpecCapitalization { + int aField; + WithWithJavaBeansSpecCapitalization(int aField) { + super(); + } + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + public @java.lang.SuppressWarnings("all") WithWithJavaBeansSpecCapitalization withaField(final int aField) { + return ((this.aField == aField) ? this : new WithWithJavaBeansSpecCapitalization(aField)); + } +} diff --git a/test/transform/resource/before/BuilderWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/BuilderWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..db1fe15f --- /dev/null +++ b/test/transform/resource/before/BuilderWithJavaBeansSpecCapitalization.java @@ -0,0 +1,7 @@ +//CONF: lombok.accessors.capitalization = beanspec +@lombok.Builder(setterPrefix = "set") +class BuilderWithJavaBeansSpecCapitalization { + @lombok.Singular("z") java.util.List a; + @lombok.Singular("yField") java.util.List aField; + String bField; +} diff --git a/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java index 3c27317c..68f41e3d 100644 --- a/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java +++ b/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java @@ -1,11 +1,5 @@ -class GetterWithoutJavaBeansSpecCapitalization { - @lombok.Getter int a; - @lombok.Getter int aField; -} - -@lombok.experimental.Accessors(javaBeansSpecCapitalization=true) +//CONF: lombok.accessors.capitalization = beanspec class GetterWithJavaBeansSpecCapitalization { @lombok.Getter int a; @lombok.Getter int aField; } - diff --git a/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java index 80a1b4ee..b5e34ba7 100644 --- a/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java +++ b/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java @@ -1,11 +1,5 @@ -class SetterWithoutJavaBeansSpecCapitalization { - @lombok.Setter int a; - @lombok.Setter int aField; -} - -@lombok.experimental.Accessors(javaBeansSpecCapitalization=true) +//CONF: lombok.accessors.capitalization = beanspec class SetterWithJavaBeansSpecCapitalization { @lombok.Setter int a; @lombok.Setter int aField; } - diff --git a/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java index f0044ed9..7c001f6e 100644 --- a/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java +++ b/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java @@ -1,10 +1,5 @@ +//CONF: lombok.accessors.capitalization = beanspec @lombok.Value -@lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class ValueWithJavaBeansSpecCapitalization { final int aField; } - -@lombok.Value -class ValueWithoutJavaBeansSpecCapitalization { - final int aField; -} diff --git a/test/transform/resource/before/WithOnJavaBeansSpecCapitalization.java b/test/transform/resource/before/WithOnJavaBeansSpecCapitalization.java deleted file mode 100644 index 476fb5a4..00000000 --- a/test/transform/resource/before/WithOnJavaBeansSpecCapitalization.java +++ /dev/null @@ -1,16 +0,0 @@ -@lombok.With -@lombok.experimental.Accessors(javaBeansSpecCapitalization = true) -class WithOnJavaBeansSpecCapitalization { - int aField; - - WithOnJavaBeansSpecCapitalization(int aField) { - } -} - -@lombok.With -class WithOffJavaBeansSpecCapitalization { - int aField; - - WithOffJavaBeansSpecCapitalization(int aField) { - } -} diff --git a/test/transform/resource/before/WithWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/WithWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..ef4a78ad --- /dev/null +++ b/test/transform/resource/before/WithWithJavaBeansSpecCapitalization.java @@ -0,0 +1,8 @@ +//CONF: lombok.accessors.capitalization = beanspec +@lombok.With +class WithWithJavaBeansSpecCapitalization { + int aField; + + WithWithJavaBeansSpecCapitalization(int aField) { + } +} -- cgit From 13d84b129e562fdc71b049778c3b3bd2376e29a4 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 18 Oct 2021 16:01:01 +0200 Subject: [#2693] Docs and changelog for the ‘accessors.capitalization = beanspec’ feature. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/changelog.markdown | 2 +- website/templates/features/GetterSetter.html | 5 +++++ website/templates/features/With.html | 9 +++++++++ website/templates/features/experimental/Accessors.html | 12 +++++++++--- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 6f9adbac..cd8a4353 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -2,7 +2,7 @@ Lombok Changelog ---------------- ### v1.18.24 "Edgy Guinea Pig" -* No new changes since the release of v1.18.22. +* FEATURE: Turning a field named `uShape` into a getter is tricky: `getUShape` or `getuShape`? The community is split on which style to use. Lombok does `getUShape`, but if you prefer the `getuShape` style, add to `lombok.config`: `lombok.accessors.capitalization = beanspec`. [Issue #2693](https://github.com/projectlombok/lombok/issues/2693) [Pull Request #2996](https://github.com/projectlombok/lombok/pull/2996). Thanks __@YonathanSherwin__! ### v1.18.22 (October 6th, 2021) * PLATFORM: JDK17 support added. [Issue #2898](https://github.com/projectlombok/lombok/issues/2898). diff --git a/website/templates/features/GetterSetter.html b/website/templates/features/GetterSetter.html index a429c9ac..8b16d34d 100644 --- a/website/templates/features/GetterSetter.html +++ b/website/templates/features/GetterSetter.html @@ -37,6 +37,11 @@ lombok.getter.noIsPrefix = [true | false] (default: false)

If set to true, getters generated for boolean fields will use the get prefix instead of the defaultis prefix, and any generated code that calls getters, such as @ToString, will also use get instead of is +
+ lombok.accessors.capitalization = [basic | beanspec] (default: basic) +
+ Controls how tricky cases like uShaped (one lowercase letter followed by an upper/titlecase letter) are capitalized. basic capitalizes that to getUShaped, and beanspec capitalizes that to getuShaped instead.
+ Both strategies are commonly used in the java ecosystem, though beanspec is more common.
lombok.setter.flagUsage = [warning | error] (default: not set)
diff --git a/website/templates/features/With.html b/website/templates/features/With.html index 8b34f038..867c17eb 100644 --- a/website/templates/features/With.html +++ b/website/templates/features/With.html @@ -27,6 +27,15 @@ <@f.snippets name="With" /> <@f.confKeys> + <>
+ lombok.accessors.prefix += a field prefix (default: empty list) +
+ This is a list property; entries can be added with the += operator. Inherited prefixes from parent config files can be removed with the -= operator. Lombok will strip any matching field prefix from the name of a field in order to determine the name of the getter/setter to generate. For example, if m is one of the prefixes listed in this setting, then a field named mFoobar will result in a getter named getFoobar(), not getMFoobar(). An explicitly configured prefix parameter of an @Accessors annotation takes precedence over this setting. +
+ lombok.accessors.capitalization = [basic | beanspec] (default: basic) +
+ Controls how tricky cases like uShaped (one lowercase letter followed by an upper/titlecase letter) are capitalized. basic capitalizes that to withUShaped, and beanspec capitalizes that to withuShaped instead.
+ Both strategies are commonly used in the java ecosystem, though beanspec is more common.
lombok.with.flagUsage = [warning | error] (default: not set)
diff --git a/website/templates/features/experimental/Accessors.html b/website/templates/features/experimental/Accessors.html index 564ab66d..9a9385cb 100644 --- a/website/templates/features/experimental/Accessors.html +++ b/website/templates/features/experimental/Accessors.html @@ -4,9 +4,11 @@ <@f.history>

@Accessors was introduced as experimental feature in lombok v0.11.0. +

+ The lombok.config option lombok.accessors.capitalization = [basic | beanspec] was added in lombok v1.18.24.

- + <@f.experimental>
  • @@ -17,7 +19,6 @@
Current status: neutral - Some changes are expected. These changes are intended to be backwards compatible, but should start in an experimental feature:
    -
  • Open feature request: naming behaviour for properties that start with a lowercase letter followed by an uppercase letter. Half of specs, tools and lombok users prefer that a field named uLimit into getULimit (including lombok) and the other half turn prefer getuLimit. @Accessors may be involved in any update that addresses this request.
  • Open feature request: More control over naming accessors; for example to address creatively named boolean properties: Turn boolean wasRunning into boolean wasRunning() instead of boolean isWasRunning(), as well as more expansive prefix support. @Accessors will be involved if this feature request is addressed.
  • @Accessors currently does not 'cascade' from field @Accessors annotation to the class-level @Accessors annotation, but it does 'cascade' to lombok.config. Changing this is not difficult but backwards incompatible. It's not likely to break much existing code, but this needs to be decided on before the feature can move out of experimental status.
@@ -44,7 +45,7 @@

- The @Accessors annotation is legal on types and fields; the annotation that applies is the one on the field if present, otherwise the one on the class. When a @Accessors annotation on a field is present, any @Accessors annotation also present on the class the field is in, is entirely ignored, even for properties not configured on the field @Accessors. This in contrast to any lombok.config configuration keys which serve as fall-back default if any explicit @Accessors annotation doesn't specify. + The @Accessors annotation is legal on types and fields; the annotation that applies is the one on the field if present, otherwise the one on the class. When an @Accessors annotation on a field is present, any @Accessors annotation also present on the class the field is in, is entirely ignored, even for properties not configured on the field @Accessors. This in contrast to any lombok.config configuration keys which serve as fall-back default if any explicit @Accessors annotation doesn't specify.

@@ -63,6 +64,11 @@ lombok.accessors.prefix += a field prefix (default: empty list)
This is a list property; entries can be added with the += operator. Inherited prefixes from parent config files can be removed with the -= operator. Any class that either doesn't have an @Accessors annotation, or it does, but that annotation does not have an explicit value for the prefix parameter, will act as if @Accessors(prefix = {prefixes listed in configuration}) is present. +
+ lombok.accessors.capitalization = [basic | beanspec] (default: basic) +
+ Controls how tricky cases like uShaped (one lowercase letter followed by an upper/titlecase letter) are capitalized. basic capitalizes that to getUShaped, and beanspec capitalizes that to getuShaped instead.
+ Both strategies are commonly used in the java ecosystem, though beanspec is more common.
lombok.accessors.flagUsage = [warning | error] (default: not set)
-- cgit From 890028646a93551c704f316e43348c13904193cd Mon Sep 17 00:00:00 2001 From: ysherwin Date: Tue, 19 Oct 2021 14:01:28 +0300 Subject: fixing beanspec tests --- .../ValueWithJavaBeansSpecCapitalization.java | 35 +--------------------- .../WithWithJavaBeansSpecCapitalization.java | 2 +- 2 files changed, 2 insertions(+), 35 deletions(-) diff --git a/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java index b92dd5b6..543481e8 100644 --- a/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java +++ b/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java @@ -30,37 +30,4 @@ final class ValueWithJavaBeansSpecCapitalization { public java.lang.String toString() { return "ValueWithJavaBeansSpecCapitalization(aField=" + this.getaField() + ")"; } -} -final class ValueWithoutJavaBeansSpecCapitalization { - private final int aField; - @java.lang.SuppressWarnings("all") - public ValueWithoutJavaBeansSpecCapitalization(final int aField) { - this.aField = aField; - } - @java.lang.SuppressWarnings("all") - public int getAField() { - return this.aField; - } - @java.lang.Override - @java.lang.SuppressWarnings("all") - public boolean equals(final java.lang.Object o) { - if (o == this) return true; - if (!(o instanceof ValueWithoutJavaBeansSpecCapitalization)) return false; - final ValueWithoutJavaBeansSpecCapitalization other = (ValueWithoutJavaBeansSpecCapitalization) o; - if (this.getAField() != other.getAField()) return false; - return true; - } - @java.lang.Override - @java.lang.SuppressWarnings("all") - public int hashCode() { - final int PRIME = 59; - int result = 1; - result = result * PRIME + this.getAField(); - return result; - } - @java.lang.Override - @java.lang.SuppressWarnings("all") - public java.lang.String toString() { - return "ValueWithoutJavaBeansSpecCapitalization(aField=" + this.getAField() + ")"; - } -} +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/WithWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/WithWithJavaBeansSpecCapitalization.java index d530ad8a..fb035da4 100644 --- a/test/transform/resource/after-ecj/WithWithJavaBeansSpecCapitalization.java +++ b/test/transform/resource/after-ecj/WithWithJavaBeansSpecCapitalization.java @@ -1,4 +1,4 @@ -@lombok.With class WithOnJavaBeansSpecCapitalization { +@lombok.With class WithWithJavaBeansSpecCapitalization { int aField; WithWithJavaBeansSpecCapitalization(int aField) { super(); -- cgit From 553b25addde4fab136258f7718e274a98bfbe34a Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Thu, 21 Oct 2021 10:38:37 +0200 Subject: [fixes #2985] Resolve var/val only once in eclipse --- buildScripts/tests.ant.xml | 16 +++- .../lombok/eclipse/agent/EclipsePatcher.java | 1 + .../lombok/eclipse/agent/PatchVal.java | 85 +++++++++++----------- test/core/src/lombok/DirectoryRunner.java | 3 +- test/core/src/lombok/RunTestsViaEcj.java | 26 +++++-- .../after-delombok/ValInvalidParameter.java | 29 ++++++++ test/transform/resource/after-ecj/ValErrors.java | 4 +- .../resource/after-ecj/ValInvalidParameter.java | 29 ++++++++ .../resource/before/ValInvalidParameter.java | 32 ++++++++ .../ValInvalidParameter.java.messages | 1 + .../resource/messages-ecj/ValErrors.java.messages | 6 +- .../messages-ecj/ValInBasicFor.java.messages | 6 +- .../messages-ecj/ValInvalidParameter.java.messages | 9 +++ .../ValInvalidParameter.java.messages | 9 +++ 14 files changed, 194 insertions(+), 62 deletions(-) create mode 100644 test/transform/resource/after-delombok/ValInvalidParameter.java create mode 100644 test/transform/resource/after-ecj/ValInvalidParameter.java create mode 100644 test/transform/resource/before/ValInvalidParameter.java create mode 100644 test/transform/resource/messages-delombok/ValInvalidParameter.java.messages create mode 100644 test/transform/resource/messages-ecj/ValInvalidParameter.java.messages create mode 100644 test/transform/resource/messages-idempotent/ValInvalidParameter.java.messages diff --git a/buildScripts/tests.ant.xml b/buildScripts/tests.ant.xml index 9d9e9541..838ac353 100644 --- a/buildScripts/tests.ant.xml +++ b/buildScripts/tests.ant.xml @@ -152,13 +152,18 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn + - Running TestEclipse on eclipse-@{version} on JVM${ant.java.version}. + + + + Running TestEclipse on eclipse-@{version} on JVM${ant.java.version} using. Compiler compliance level: @{compiler.compliance.level} + @@ -175,11 +180,16 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn - + + + + + + @@ -217,5 +227,5 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn - + diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 328860e3..33dad64e 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -764,6 +764,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { sm.addScript(ScriptBuilder.replaceMethodCall() .target(new MethodTarget(LOCALDECLARATION_SIG, "resolve", "void", BLOCKSCOPE_SIG)) + .target(new MethodTarget(LOCALDECLARATION_SIG, "resolve", "void", BLOCKSCOPE_SIG, "boolean")) .methodToReplace(new Hook(EXPRESSION_SIG, "resolveType", TYPEBINDING_SIG, BLOCKSCOPE_SIG)) .requestExtra(StackRequest.THIS) .replacementMethod(new Hook("lombok.launch.PatchFixesHider$Val", "skipResolveInitializerIfAlreadyCalled2", TYPEBINDING_SIG, EXPRESSION_SIG, BLOCKSCOPE_SIG, LOCALDECLARATION_SIG)) diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index 3e96e75d..e758979d 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -35,13 +35,11 @@ import org.eclipse.jdt.internal.compiler.ast.FunctionalExpression; import org.eclipse.jdt.internal.compiler.ast.ImportReference; import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; -import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; @@ -250,7 +248,6 @@ public class PatchVal { } TypeBinding resolved = null; - Constant oldConstant = init.constant; try { resolved = decomponent ? getForEachComponentType(init, scope) : resolveForExpression(init, scope); } catch (NullPointerException e) { @@ -260,6 +257,46 @@ public class PatchVal { // just go with 'Object' and let the IDE print the appropriate errors. resolved = null; } + + if (resolved == null) { + if (init instanceof ConditionalExpression) { + ConditionalExpression cexp = (ConditionalExpression) init; + Expression ifTrue = cexp.valueIfTrue; + Expression ifFalse = cexp.valueIfFalse; + TypeBinding ifTrueResolvedType = ifTrue.resolvedType; + CompilationResult compilationResult = scope.referenceCompilationUnit().compilationResult; + CategorizedProblem[] problems = compilationResult.problems; + CategorizedProblem lastProblem = problems[compilationResult.problemCount - 1]; + if (ifTrueResolvedType != null && ifFalse.resolvedType == null && lastProblem.getCategoryID() == CAT_TYPE) { + int problemCount = compilationResult.problemCount; + for (int i = 0; i < problemCount; ++i) { + if (problems[i] == lastProblem) { + problems[i] = null; + if (i + 1 < problemCount) { + System.arraycopy(problems, i + 1, problems, i, problemCount - i + 1); + } + break; + } + } + compilationResult.removeProblem(lastProblem); + if (!compilationResult.hasErrors()) { + clearIgnoreFurtherInvestigationField(scope.referenceContext()); + setValue(getField(CompilationResult.class, "hasMandatoryErrors"), compilationResult, false); + } + + if (ifFalse instanceof FunctionalExpression) { + FunctionalExpression functionalExpression = (FunctionalExpression) ifFalse; + functionalExpression.setExpectedType(ifTrueResolvedType); + } + if (ifFalse.resolvedType == null) { + resolveForExpression(ifFalse, scope); + } + + resolved = ifTrueResolvedType; + } + } + } + if (resolved != null) { try { replacement = makeType(resolved, local.type, false); @@ -267,10 +304,6 @@ public class PatchVal { } catch (Exception e) { // Some type thing failed. } - } else { - if (init instanceof MessageSend && ((MessageSend) init).actualReceiverType == null) { - init.constant = oldConstant; - } } } @@ -370,43 +403,7 @@ public class PatchVal { // Known cause of issues; for example: val e = mth("X"), where mth takes 2 arguments. return null; } catch (AbortCompilation e) { - if (collection instanceof ConditionalExpression) { - ConditionalExpression cexp = (ConditionalExpression) collection; - Expression ifTrue = cexp.valueIfTrue; - Expression ifFalse = cexp.valueIfFalse; - TypeBinding ifTrueResolvedType = ifTrue.resolvedType; - CategorizedProblem problem = e.problem; - if (ifTrueResolvedType != null && ifFalse.resolvedType == null && problem.getCategoryID() == CAT_TYPE) { - CompilationResult compilationResult = e.compilationResult; - CategorizedProblem[] problems = compilationResult.problems; - int problemCount = compilationResult.problemCount; - for (int i = 0; i < problemCount; ++i) { - if (problems[i] == problem) { - problems[i] = null; - if (i + 1 < problemCount) { - System.arraycopy(problems, i + 1, problems, i, problemCount - i + 1); - } - break; - } - } - compilationResult.removeProblem(problem); - if (!compilationResult.hasErrors()) { - clearIgnoreFurtherInvestigationField(scope.referenceContext()); - setValue(getField(CompilationResult.class, "hasMandatoryErrors"), compilationResult, false); - } - - if (ifFalse instanceof FunctionalExpression) { - FunctionalExpression functionalExpression = (FunctionalExpression) ifFalse; - functionalExpression.setExpectedType(ifTrueResolvedType); - } - if (ifFalse.resolvedType == null) { - ifFalse.resolve(scope); - } - - return ifTrueResolvedType; - } - } - throw e; + return null; } } diff --git a/test/core/src/lombok/DirectoryRunner.java b/test/core/src/lombok/DirectoryRunner.java index b041c42e..53347e24 100644 --- a/test/core/src/lombok/DirectoryRunner.java +++ b/test/core/src/lombok/DirectoryRunner.java @@ -55,7 +55,8 @@ public class DirectoryRunner extends Runner { }, ECJ { @Override public int getVersion() { - return Eclipse.getEcjCompilerVersion(); + String javaVersionString = System.getProperty("compiler.compliance.level"); + return javaVersionString != null ? Integer.parseInt(javaVersionString) : Eclipse.getEcjCompilerVersion(); } }; diff --git a/test/core/src/lombok/RunTestsViaEcj.java b/test/core/src/lombok/RunTestsViaEcj.java index afba8c7f..6137de49 100644 --- a/test/core/src/lombok/RunTestsViaEcj.java +++ b/test/core/src/lombok/RunTestsViaEcj.java @@ -64,9 +64,22 @@ import org.osgi.framework.BundleContext; public class RunTestsViaEcj extends AbstractRunTests { protected CompilerOptions ecjCompilerOptions() { CompilerOptions options = new CompilerOptions(); - options.complianceLevel = Eclipse.getLatestEcjCompilerVersionConstant(); - options.sourceLevel = Eclipse.getLatestEcjCompilerVersionConstant(); - options.targetJDK = Eclipse.getLatestEcjCompilerVersionConstant(); + Map warnings = new HashMap(); + + String javaVersionString = System.getProperty("compiler.compliance.level"); + long ecjCompilerVersionConstant = Eclipse.getLatestEcjCompilerVersionConstant(); + long ecjCompilerVersion = Eclipse.getEcjCompilerVersion(); + if (javaVersionString != null) { + long javaVersion = Long.parseLong(javaVersionString); + ecjCompilerVersionConstant = (javaVersion + 44) << 16; + ecjCompilerVersion = javaVersion; + } else { + // Preview features are only allowed if the maximum compiler version is equal to the source version + warnings.put("org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures", "enabled"); + } + options.complianceLevel = ecjCompilerVersionConstant; + options.sourceLevel = ecjCompilerVersionConstant; + options.targetJDK = ecjCompilerVersionConstant; options.docCommentSupport = false; options.parseLiteralExpressionsAsConstants = true; options.inlineJsrBytecode = true; @@ -78,17 +91,14 @@ public class RunTestsViaEcj extends AbstractRunTests { options.reportUnusedParameterWhenOverridingConcrete = false; options.reportDeadCodeInTrivialIfStatement = false; options.generateClassFiles = false; - Map warnings = new HashMap(); warnings.put(CompilerOptions.OPTION_ReportUnusedLocal, "ignore"); warnings.put(CompilerOptions.OPTION_ReportUnusedLabel, "ignore"); warnings.put(CompilerOptions.OPTION_ReportUnusedImport, "ignore"); warnings.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, "ignore"); warnings.put(CompilerOptions.OPTION_ReportIndirectStaticAccess, "warning"); warnings.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, "warning"); - warnings.put("org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures", "enabled"); warnings.put("org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures", "ignore"); - int ecjVersion = Eclipse.getEcjCompilerVersion(); - warnings.put(CompilerOptions.OPTION_Source, (ecjVersion < 9 ? "1." : "") + ecjVersion); + warnings.put(CompilerOptions.OPTION_Source, (ecjCompilerVersion < 9 ? "1." : "") + ecjCompilerVersion); options.set(warnings); return options; } @@ -96,7 +106,7 @@ public class RunTestsViaEcj extends AbstractRunTests { protected IErrorHandlingPolicy ecjErrorHandlingPolicy() { return new IErrorHandlingPolicy() { public boolean stopOnFirstError() { - return true; + return false; } public boolean proceedOnErrors() { diff --git a/test/transform/resource/after-delombok/ValInvalidParameter.java b/test/transform/resource/after-delombok/ValInvalidParameter.java new file mode 100644 index 00000000..f3d4229c --- /dev/null +++ b/test/transform/resource/after-delombok/ValInvalidParameter.java @@ -0,0 +1,29 @@ +public class ValInvalidParameter { + public void val() { + final java.lang.Object a = a(new NonExistingClass()); + final java.lang.Object b = a(a(new NonExistingClass())); + final java.lang.Object c = nonExisitingMethod(b(1)); + final java.lang.Object d = nonExistingObject.nonExistingMethod(); + final java.lang.Object e = b(1).nonExistingMethod(); + final java.lang.Object f = 1 > 2 ? a(new NonExistingClass()) : a(new NonExistingClass()); + final java.lang.Object g = b2(1); + final java.lang.Integer h = b2(a("a"), a(null)); + final int i = a(a(null)); + } + + public int a(String param) { + return 0; + } + + public int a(Integer param) { + return 0; + } + + public Integer b(int i) { + return i; + } + + public Integer b2(int i, int j) { + return i; + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValErrors.java b/test/transform/resource/after-ecj/ValErrors.java index 1bd61f87..19c2facd 100644 --- a/test/transform/resource/after-ecj/ValErrors.java +++ b/test/transform/resource/after-ecj/ValErrors.java @@ -4,9 +4,9 @@ public class ValErrors { super(); } public void unresolvableExpression() { - val c = d; + final @val java.lang.Object c = d; } public void arrayInitializer() { - val e = {"foo", "bar"}; + final @val java.lang.Object e = {"foo", "bar"}; } } \ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValInvalidParameter.java b/test/transform/resource/after-ecj/ValInvalidParameter.java new file mode 100644 index 00000000..14549aa7 --- /dev/null +++ b/test/transform/resource/after-ecj/ValInvalidParameter.java @@ -0,0 +1,29 @@ +import lombok.val; +public class ValInvalidParameter { + public ValInvalidParameter() { + super(); + } + public void val() { + final @val java.lang.Object a = a(new NonExistingClass()); + final @val java.lang.Object b = a(a(new NonExistingClass())); + final @val java.lang.Object c = nonExisitingMethod(b(1)); + final @val java.lang.Object d = nonExistingObject.nonExistingMethod(); + final @val java.lang.Object e = b(1).nonExistingMethod(); + final @val java.lang.Object f = ((1 > 2) ? a(new NonExistingClass()) : a(new NonExistingClass())); + final @val java.lang.Object g = b2(1); + final @val java.lang.Object h = b2(a("a"), a(null)); + final @val java.lang.Object i = a(a(null)); + } + public int a(String param) { + return 0; + } + public int a(Integer param) { + return 0; + } + public Integer b(int i) { + return i; + } + public Integer b2(int i, int j) { + return i; + } +} \ No newline at end of file diff --git a/test/transform/resource/before/ValInvalidParameter.java b/test/transform/resource/before/ValInvalidParameter.java new file mode 100644 index 00000000..f4961c4e --- /dev/null +++ b/test/transform/resource/before/ValInvalidParameter.java @@ -0,0 +1,32 @@ +//version :9 +import lombok.val; + +public class ValInvalidParameter { + public void val() { + val a = a(new NonExistingClass()); + val b = a(a(new NonExistingClass())); + val c = nonExisitingMethod(b(1)); + val d = nonExistingObject.nonExistingMethod(); + val e = b(1).nonExistingMethod(); + val f = 1 > 2 ? a(new NonExistingClass()) : a(new NonExistingClass()); + val g = b2(1); + val h = b2(a("a"), a(null)); + val i = a(a(null)); + } + + public int a(String param) { + return 0; + } + + public int a(Integer param) { + return 0; + } + + public Integer b(int i) { + return i; + } + + public Integer b2(int i, int j) { + return i; + } +} \ No newline at end of file diff --git a/test/transform/resource/messages-delombok/ValInvalidParameter.java.messages b/test/transform/resource/messages-delombok/ValInvalidParameter.java.messages new file mode 100644 index 00000000..da0df315 --- /dev/null +++ b/test/transform/resource/messages-delombok/ValInvalidParameter.java.messages @@ -0,0 +1 @@ +12 Cannot use 'val' here because initializer expression does not have a representable type: Type cannot be resolved \ No newline at end of file diff --git a/test/transform/resource/messages-ecj/ValErrors.java.messages b/test/transform/resource/messages-ecj/ValErrors.java.messages index c4c76901..9fcec493 100644 --- a/test/transform/resource/messages-ecj/ValErrors.java.messages +++ b/test/transform/resource/messages-ecj/ValErrors.java.messages @@ -1,2 +1,4 @@ -6 d cannot be resolved to a variable -10 'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... }) +7 d cannot be resolved to a variable +7 d cannot be resolved or is not a field +11 'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... }) +11 Type mismatch: cannot convert from String[] to Object \ No newline at end of file diff --git a/test/transform/resource/messages-ecj/ValInBasicFor.java.messages b/test/transform/resource/messages-ecj/ValInBasicFor.java.messages index b32eabe4..00bc643f 100644 --- a/test/transform/resource/messages-ecj/ValInBasicFor.java.messages +++ b/test/transform/resource/messages-ecj/ValInBasicFor.java.messages @@ -1,2 +1,4 @@ -7 'val' is not allowed in old-style for loops -7 Type mismatch: cannot convert from int to val +8 'val' is not allowed in old-style for loops +8 Type mismatch: cannot convert from int to val +8 Type mismatch: cannot convert from String to val +8 Type mismatch: cannot convert from double to val \ No newline at end of file diff --git a/test/transform/resource/messages-ecj/ValInvalidParameter.java.messages b/test/transform/resource/messages-ecj/ValInvalidParameter.java.messages new file mode 100644 index 00000000..cbf2d7c4 --- /dev/null +++ b/test/transform/resource/messages-ecj/ValInvalidParameter.java.messages @@ -0,0 +1,9 @@ +5 NonExistingClass cannot be resolved to a type +6 NonExistingClass cannot be resolved to a type +7 The method nonExisitingMethod(Integer) is undefined for the type ValInvalidParameter +8 nonExistingObject cannot be resolved +9 The method nonExistingMethod() is undefined for the type Integer +10 NonExistingClass cannot be resolved to a type +11 The method b2(int, int) in the type ValInvalidParameter is not applicable for the arguments (int) +12 The method a(String) is ambiguous for the type ValInvalidParameter +13 The method a(String) is ambiguous for the type ValInvalidParameter \ No newline at end of file diff --git a/test/transform/resource/messages-idempotent/ValInvalidParameter.java.messages b/test/transform/resource/messages-idempotent/ValInvalidParameter.java.messages new file mode 100644 index 00000000..539d29cd --- /dev/null +++ b/test/transform/resource/messages-idempotent/ValInvalidParameter.java.messages @@ -0,0 +1,9 @@ +3 cannot find symbol +4 cannot find symbol +5 cannot find symbol +6 cannot find symbol +7 cannot find symbol +8 cannot find symbol +9 method b2 in class ValInvalidParameter cannot be applied to given types; +10 reference to a is ambiguous +11 reference to a is ambiguous \ No newline at end of file -- cgit From 1d7db8c4dfa2f7a26d9816398947f6e76e506093 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Fri, 22 Oct 2021 10:15:29 +0200 Subject: [fixes #2995] Skip records for field defaults via config --- src/core/lombok/eclipse/handlers/HandleFieldDefaults.java | 2 ++ src/core/lombok/javac/handlers/HandleFieldDefaults.java | 2 ++ .../after-delombok/FieldDefaultsViaConfigOnRecord.java | 3 +++ .../resource/after-ecj/FieldDefaultsViaConfigOnRecord.java | 10 ++++++++++ .../resource/before/FieldDefaultsViaConfigOnRecord.java | 7 +++++++ 5 files changed, 24 insertions(+) create mode 100644 test/transform/resource/after-delombok/FieldDefaultsViaConfigOnRecord.java create mode 100644 test/transform/resource/after-ecj/FieldDefaultsViaConfigOnRecord.java create mode 100644 test/transform/resource/before/FieldDefaultsViaConfigOnRecord.java diff --git a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java index 5900e7ed..3297ba06 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java @@ -160,6 +160,8 @@ public class HandleFieldDefaults extends EclipseASTAdapter { boolean defaultToFinal = makeFinalIsExplicit ? false : Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_FINAL_EVERYWHERE)); if (!defaultToPrivate && !defaultToFinal && fieldDefaults == null) return; + // Do not apply field defaults to records if set using the the config system + if (fieldDefaults == null && !isClassOrEnum(typeNode)) return; AccessLevel fdAccessLevel = (fieldDefaults != null && levelIsExplicit) ? fd.level() : defaultToPrivate ? AccessLevel.PRIVATE : null; boolean fdToFinal = (fieldDefaults != null && makeFinalIsExplicit) ? fd.makeFinal() : defaultToFinal; diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java index ebab67e3..9a6632dd 100644 --- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java @@ -140,6 +140,8 @@ public class HandleFieldDefaults extends JavacASTAdapter { boolean defaultToFinal = makeFinalIsExplicit ? false : Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_FINAL_EVERYWHERE)); if (!defaultToPrivate && !defaultToFinal && fieldDefaults == null) return; + // Do not apply field defaults to records if set using the the config system + if (fieldDefaults == null && !isClassOrEnum(typeNode)) return; AccessLevel fdAccessLevel = (fieldDefaults != null && levelIsExplicit) ? fd.level() : defaultToPrivate ? AccessLevel.PRIVATE : null; boolean fdToFinal = (fieldDefaults != null && makeFinalIsExplicit) ? fd.makeFinal() : defaultToFinal; diff --git a/test/transform/resource/after-delombok/FieldDefaultsViaConfigOnRecord.java b/test/transform/resource/after-delombok/FieldDefaultsViaConfigOnRecord.java new file mode 100644 index 00000000..1a2ce882 --- /dev/null +++ b/test/transform/resource/after-delombok/FieldDefaultsViaConfigOnRecord.java @@ -0,0 +1,3 @@ +// version 14: +public record FieldDefaultsViaConfigOnRecord(String a, String b) { +} diff --git a/test/transform/resource/after-ecj/FieldDefaultsViaConfigOnRecord.java b/test/transform/resource/after-ecj/FieldDefaultsViaConfigOnRecord.java new file mode 100644 index 00000000..44ef0d4c --- /dev/null +++ b/test/transform/resource/after-ecj/FieldDefaultsViaConfigOnRecord.java @@ -0,0 +1,10 @@ +// version 14: +public record FieldDefaultsViaConfigOnRecord(String a, String b) { +/* Implicit */ private final String a; +/* Implicit */ private final String b; + public FieldDefaultsViaConfigOnRecord(String a, String b) { + super(); + .a = a; + .b = b; + } +} \ No newline at end of file diff --git a/test/transform/resource/before/FieldDefaultsViaConfigOnRecord.java b/test/transform/resource/before/FieldDefaultsViaConfigOnRecord.java new file mode 100644 index 00000000..e72179e9 --- /dev/null +++ b/test/transform/resource/before/FieldDefaultsViaConfigOnRecord.java @@ -0,0 +1,7 @@ +// version 14: +//CONF: lombok.fieldDefaults.defaultFinal = true +//CONF: lombok.fieldDefaults.defaultPrivate = true +//unchanged + +public record FieldDefaultsViaConfigOnRecord(String a, String b) { +} \ No newline at end of file -- cgit From f6e897e486b76548d76a8b16f90516e0cab42985 Mon Sep 17 00:00:00 2001 From: Fatima Rami Date: Sat, 23 Oct 2021 21:49:42 +0200 Subject: [Fixes#3008] @Witer replaced by @With --- website/templates/features/Value.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/templates/features/Value.html b/website/templates/features/Value.html index c41b6b10..e128383f 100644 --- a/website/templates/features/Value.html +++ b/website/templates/features/Value.html @@ -5,7 +5,7 @@

@Value was introduced as experimental feature in lombok v0.11.4.

- @Value no longer implies @Wither since lombok v0.11.8. + @Value no longer implies @With since lombok v0.11.8.

@Value promoted to the main lombok package since lombok v0.12.0.

-- cgit From 3565bc836e7e6e10a2ec9c3f35f42102b9ba55bf Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Sat, 23 Oct 2021 21:54:53 +0200 Subject: [fixes #3008] [docs] The docs for `@Value` were still referring to `@Wither` instead of `@With` --- website/templates/features/Value.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/templates/features/Value.html b/website/templates/features/Value.html index c41b6b10..e128383f 100644 --- a/website/templates/features/Value.html +++ b/website/templates/features/Value.html @@ -5,7 +5,7 @@

@Value was introduced as experimental feature in lombok v0.11.4.

- @Value no longer implies @Wither since lombok v0.11.8. + @Value no longer implies @With since lombok v0.11.8.

@Value promoted to the main lombok package since lombok v0.12.0.

-- cgit From 7c8ba501deea24694e2502747b63aa6dab503c79 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Sat, 23 Oct 2021 21:57:06 +0200 Subject: [fixes #3008] [docs] ... and of course the usage example also mentioned `@Wither`. --- website/usageExamples/ValueExample_pre.jpage | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/usageExamples/ValueExample_pre.jpage b/website/usageExamples/ValueExample_pre.jpage index d9550c25..27b28eb7 100644 --- a/website/usageExamples/ValueExample_pre.jpage +++ b/website/usageExamples/ValueExample_pre.jpage @@ -1,12 +1,12 @@ import lombok.AccessLevel; import lombok.experimental.NonFinal; import lombok.experimental.Value; -import lombok.experimental.Wither; +import lombok.experimental.With; import lombok.ToString; @Value public class ValueExample { String name; - @Wither(AccessLevel.PACKAGE) @NonFinal int age; + @With(AccessLevel.PACKAGE) @NonFinal int age; double score; protected String[] tags; -- cgit From 746ce5d4eece628b1d66a4c60b3bae422f8d0034 Mon Sep 17 00:00:00 2001 From: Fatima Rami Date: Sat, 23 Oct 2021 22:07:52 +0200 Subject: #1990 fixed error documentation @FieldNameConstants --- website/templates/features/experimental/FieldNameConstants.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/templates/features/experimental/FieldNameConstants.html b/website/templates/features/experimental/FieldNameConstants.html index e88b7670..06fa23b5 100644 --- a/website/templates/features/experimental/FieldNameConstants.html +++ b/website/templates/features/experimental/FieldNameConstants.html @@ -24,7 +24,7 @@

The @FieldNameConstants annotation generates an inner type which contains 1 constant for each field in your class; either string constants (fields marked public static final, of type java.lang.String) or if you prefer, an enum type with 1 value for each field - write @FieldNameConstants(asEnum = true) for the enum variant. @FieldNameConstants is useful for various marshalling and serialization frameworks. The constant field (whether enum value or string constant) always has the exact same name as the field, capitalization and all, unless you set the lombok.fieldNameConstants.uppercase = true option in your lombok.config file; in that case lombok will try to UPPER_CASE the name.

- The generated inner type is by default called Fields and is public. You can modify this via @FieldNameConstants(innerTypeName = "FieldNames", access = AccessLevel.PACKAGE) for example. The default inner type name can also be modified via configuration key lombok.fieldNameConstants.innerTypeName. The generated fields are always public. + The generated inner type is by default called Fields and is public. You can modify this via @FieldNameConstants(innerTypeName = "FieldNames", level = AccessLevel.PACKAGE) for example. The default inner type name can also be modified via configuration key lombok.fieldNameConstants.innerTypeName. The generated fields are always public.

Must be applied to classes (or enums, though you'd rarely want to do that). By default includes all non-transient, non-static fields. You can use @FieldNameConstants.Include in fields + @FieldNameConstants(onlyExplicitlyIncluded = true), or @FieldNameConstants.Exclude for more fine-grained control.

-- cgit From c359a4b41f2800c63ad28037fe02ccf8910dcc2e Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 26 Oct 2021 03:49:23 +0200 Subject: [issue #3014] test-case that reproduces this problem. --- test/core/src/lombok/DirectoryRunner.java | 1 + test/core/src/lombok/LombokTestSource.java | 4 ++++ test/transform/resource/before/BuilderNestedInEnum.java | 12 ++++++++++++ 3 files changed, 17 insertions(+) create mode 100644 test/transform/resource/before/BuilderNestedInEnum.java diff --git a/test/core/src/lombok/DirectoryRunner.java b/test/core/src/lombok/DirectoryRunner.java index 53347e24..65e5e002 100644 --- a/test/core/src/lombok/DirectoryRunner.java +++ b/test/core/src/lombok/DirectoryRunner.java @@ -40,6 +40,7 @@ import lombok.javac.Javac; public class DirectoryRunner extends Runner { /** Add 1 or more file names to reduce the testset to just the named file(s). No files = test it all. */ private static final List DEBUG_FOCUS_ON_FILE = Arrays.asList( + "BuilderNestedInEnum.java" ); public enum Compiler { diff --git a/test/core/src/lombok/LombokTestSource.java b/test/core/src/lombok/LombokTestSource.java index 0326dee9..27ffc31a 100644 --- a/test/core/src/lombok/LombokTestSource.java +++ b/test/core/src/lombok/LombokTestSource.java @@ -161,6 +161,7 @@ public class LombokTestSource { private static final Pattern UNCHANGED_PATTERN = Pattern.compile("^\\s*unchanged\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); private static final Pattern SKIP_COMPARE_CONTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?compare[- ]?contents?\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); private static final Pattern SKIP_IDEMPOTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?idempotent\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); + private static final Pattern ISSUE_REF_PATTERN = Pattern.compile("^\\s*issue #?\\d+(:?\\s+.*)?$", Pattern.CASE_INSENSITIVE); private LombokTestSource(File file, String content, List messages, List directives) { this.file = file; @@ -200,6 +201,9 @@ public class LombokTestSource { skipIdempotent = true; continue; } + if (ISSUE_REF_PATTERN.matcher(directive).matches()) { + continue; + } if (lc.startsWith("platform ")) { String platformDesc = lc.substring("platform ".length()); diff --git a/test/transform/resource/before/BuilderNestedInEnum.java b/test/transform/resource/before/BuilderNestedInEnum.java new file mode 100644 index 00000000..99348002 --- /dev/null +++ b/test/transform/resource/before/BuilderNestedInEnum.java @@ -0,0 +1,12 @@ +// issue #3014: Builder check if its on a non-static inner class and errors if it is. But it was erroring here even though it is on a static inner class. +class BuilderNestedInEnum { + public enum TestEnum { + FOO, BAR; + + @lombok.Builder + @lombok.Value + public static class TestBuilder { + String field; + } + } +} \ No newline at end of file -- cgit From 3a0176fd907ec594194cabf843a5681fd7b811fd Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 26 Oct 2021 04:14:46 +0200 Subject: [fixes #3014] Detecting whether inner classes are static wouldn't work if placed inside an enum or interface. --- src/core/lombok/eclipse/EclipseNode.java | 9 ++- src/core/lombok/javac/JavacNode.java | 8 ++- test/core/src/lombok/DirectoryRunner.java | 1 - .../after-delombok/BuilderNestedInEnum.java | 70 ++++++++++++++++++++++ .../resource/after-ecj/BuilderNestedInEnum.java | 68 +++++++++++++++++++++ 5 files changed, 149 insertions(+), 7 deletions(-) create mode 100644 test/transform/resource/after-delombok/BuilderNestedInEnum.java create mode 100644 test/transform/resource/after-ecj/BuilderNestedInEnum.java diff --git a/src/core/lombok/eclipse/EclipseNode.java b/src/core/lombok/eclipse/EclipseNode.java index 4f86f0a5..4950aeef 100644 --- a/src/core/lombok/eclipse/EclipseNode.java +++ b/src/core/lombok/eclipse/EclipseNode.java @@ -215,13 +215,16 @@ public class EclipseNode extends lombok.core.LombokNode DEBUG_FOCUS_ON_FILE = Arrays.asList( - "BuilderNestedInEnum.java" ); public enum Compiler { diff --git a/test/transform/resource/after-delombok/BuilderNestedInEnum.java b/test/transform/resource/after-delombok/BuilderNestedInEnum.java new file mode 100644 index 00000000..26dc2a06 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderNestedInEnum.java @@ -0,0 +1,70 @@ +class BuilderNestedInEnum { + public enum TestEnum { + FOO, BAR; + public static final class TestBuilder { + private final String field; + @java.lang.SuppressWarnings("all") + TestBuilder(final String field) { + this.field = field; + } + @java.lang.SuppressWarnings("all") + public static class TestBuilderBuilder { + @java.lang.SuppressWarnings("all") + private String field; + @java.lang.SuppressWarnings("all") + TestBuilderBuilder() { + } + /** + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder field(final String field) { + this.field = field; + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderNestedInEnum.TestEnum.TestBuilder build() { + return new BuilderNestedInEnum.TestEnum.TestBuilder(this.field); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder(field=" + this.field + ")"; + } + } + @java.lang.SuppressWarnings("all") + public static BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder builder() { + return new BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder(); + } + @java.lang.SuppressWarnings("all") + public String getField() { + return this.field; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof BuilderNestedInEnum.TestEnum.TestBuilder)) return false; + final BuilderNestedInEnum.TestEnum.TestBuilder other = (BuilderNestedInEnum.TestEnum.TestBuilder) o; + final java.lang.Object this$field = this.getField(); + final java.lang.Object other$field = other.getField(); + if (this$field == null ? other$field != null : !this$field.equals(other$field)) return false; + return true; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $field = this.getField(); + result = result * PRIME + ($field == null ? 43 : $field.hashCode()); + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderNestedInEnum.TestEnum.TestBuilder(field=" + this.getField() + ")"; + } + } + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/BuilderNestedInEnum.java b/test/transform/resource/after-ecj/BuilderNestedInEnum.java new file mode 100644 index 00000000..b3fb54f3 --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderNestedInEnum.java @@ -0,0 +1,68 @@ +class BuilderNestedInEnum { + public enum TestEnum { + public static final @lombok.Builder @lombok.Value class TestBuilder { + public static @java.lang.SuppressWarnings("all") class TestBuilderBuilder { + private @java.lang.SuppressWarnings("all") String field; + @java.lang.SuppressWarnings("all") TestBuilderBuilder() { + super(); + } + /** + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder field(final String field) { + this.field = field; + return this; + } + public @java.lang.SuppressWarnings("all") BuilderNestedInEnum.TestEnum.TestBuilder build() { + return new BuilderNestedInEnum.TestEnum.TestBuilder(this.field); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder(field=" + this.field) + ")"); + } + } + private final String field; + @java.lang.SuppressWarnings("all") TestBuilder(final String field) { + super(); + this.field = field; + } + public static @java.lang.SuppressWarnings("all") BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder builder() { + return new BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder(); + } + public @java.lang.SuppressWarnings("all") String getField() { + return this.field; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof BuilderNestedInEnum.TestEnum.TestBuilder))) + return false; + final BuilderNestedInEnum.TestEnum.TestBuilder other = (BuilderNestedInEnum.TestEnum.TestBuilder) o; + final java.lang.Object this$field = this.getField(); + final java.lang.Object other$field = other.getField(); + if (((this$field == null) ? (other$field != null) : (! this$field.equals(other$field)))) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $field = this.getField(); + result = ((result * PRIME) + (($field == null) ? 43 : $field.hashCode())); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("BuilderNestedInEnum.TestEnum.TestBuilder(field=" + this.getField()) + ")"); + } + } + FOO(), + BAR(), + () { + } + public TestEnum() { + super(); + } + } + BuilderNestedInEnum() { + super(); + } +} \ No newline at end of file -- cgit From 2f404f5c74327758c22af116cebfac73919a2436 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Tue, 26 Oct 2021 08:51:21 +0200 Subject: [fixes #1309] Extract interface + pull up --- .../lombok/eclipse/agent/EclipsePatcher.java | 76 +++++++++++++++++++++- .../lombok/launch/PatchFixesHider.java | 37 +++++++++-- 2 files changed, 106 insertions(+), 7 deletions(-) diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 33dad64e..06e10960 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -90,10 +90,11 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { patchListRewriteHandleGeneratedMethods(sm); patchSyntaxAndOccurrencesHighlighting(sm); patchSortMembersOperation(sm); - patchExtractInterface(sm); + patchExtractInterfaceAndPullUp(sm); patchAboutDialog(sm); patchEclipseDebugPatches(sm); patchJavadoc(sm); + patchASTConverterLiterals(sm); patchPostCompileHookEcj(sm); @@ -133,7 +134,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .transplant().build()); } - private static void patchExtractInterface(ScriptManager sm) { + private static void patchExtractInterfaceAndPullUp(ScriptManager sm) { /* Fix sourceEnding for generated nodes to avoid null pointer */ sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.compiler.SourceElementNotifier", "notifySourceElementRequestor", "void", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "org.eclipse.jdt.internal.compiler.ast.TypeDeclaration", "org.eclipse.jdt.internal.compiler.ast.ImportReference")) @@ -155,10 +156,31 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .requestExtra(StackRequest.THIS, StackRequest.PARAM4) .transplant().build()); - /* get real generated node in stead of a random one generated by the annotation */ + /* Get real node source instead of the annotation */ + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.HierarchyProcessor", "createPlaceholderForSingleVariableDeclaration", "org.eclipse.jdt.core.dom.SingleVariableDeclaration", + "org.eclipse.jdt.core.dom.SingleVariableDeclaration", + "org.eclipse.jdt.core.ICompilationUnit", + "org.eclipse.jdt.core.dom.rewrite.ASTRewrite" + )) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.HierarchyProcessor", "createPlaceholderForType", "org.eclipse.jdt.core.dom.Type", + "org.eclipse.jdt.core.dom.Type", + "org.eclipse.jdt.core.ICompilationUnit", + "org.eclipse.jdt.core.dom.rewrite.ASTRewrite" + )) + .methodToWrap(new Hook("org.eclipse.jdt.core.IBuffer", "getText", "java.lang.String", "int", "int")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getRealNodeSource", "java.lang.String", "java.lang.String", "org.eclipse.jdt.core.dom.ASTNode")) + .requestExtra(StackRequest.PARAM1) + .transplant() + .build()); + + /* Get real generated node instead of a random one generated by the annotation */ sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.replaceMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ExtractInterfaceProcessor", "createMemberDeclarations")) .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ExtractInterfaceProcessor", "createMethodComments")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor", "createAbstractMethod")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor", "addMethodStubForAbstractMethod")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor", "createChangeManager")) .methodToReplace(new Hook("org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil", "getMethodDeclarationNode", "org.eclipse.jdt.core.dom.MethodDeclaration", "org.eclipse.jdt.core.IMethod", "org.eclipse.jdt.core.dom.CompilationUnit")) .replacementMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getRealMethodDeclarationNode", "org.eclipse.jdt.core.dom.MethodDeclaration", "org.eclipse.jdt.core.IMethod", "org.eclipse.jdt.core.dom.CompilationUnit")) .transplant().build()); @@ -176,6 +198,29 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) .request(StackRequest.PARAM2) .transplant().build()); + + /* Do not add a modifier to the generating annotation during pull up + * + * Example: Pull up a protected method (canEqual()/@EqualsAndHashCode) + */ + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor$IncomingMemberVisibilityAdjustment", "rewriteVisibility")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "skipRewriteVisibility", "boolean", "org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor$IncomingMemberVisibilityAdjustment")) + .request(StackRequest.THIS) + .transplant() + .build()); + + /* + * ImportRemover sometimes removes lombok imports if a generated method/type gets changed. Skipping all generated nodes fixes this behavior. + * + * Example: Create a class (Use.java) that uses a generated method (Test t; t.toString();) and pull up this generated method. + */ + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ImportRemover", "registerRemovedNode", "void", "org.eclipse.jdt.core.dom.ASTNode")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) + .request(StackRequest.PARAM1) + .transplant() + .build()); } private static void patchAboutDialog(ScriptManager sm) { @@ -526,6 +571,13 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { "org.eclipse.jdt.core.dom.Name", "java.lang.Object")) .transplant().build()); + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.ASTNode", "boolean", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration")) + .methodToWrap(new Hook("org.eclipse.jdt.core.dom.Block", "", "void", "org.eclipse.jdt.core.dom.AST")) + .requestExtra(StackRequest.PARAM2) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlag", "void", + "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) + .transplant().build()); sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertType", "org.eclipse.jdt.core.dom.Type", "org.eclipse.jdt.internal.compiler.ast.TypeReference")) @@ -926,4 +978,22 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .build()); } + private static void patchASTConverterLiterals(ScriptManager sm) { + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.Expression", "org.eclipse.jdt.internal.compiler.ast.StringLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.Expression", "org.eclipse.jdt.internal.compiler.ast.TextBlock")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.CharacterLiteral", "org.eclipse.jdt.internal.compiler.ast.CharLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.DoubleLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.FloatLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.LongLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.LongLiteralMinValue")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.IntLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.IntLiteralMinValue")) + .methodToWrap(new Hook("java.lang.String", "", "void", "char[]", "int", "int")) + .requestExtra(StackRequest.PARAM1) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getRealNodeSource", "java.lang.String", "java.lang.String", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) + .transplant() + .build()); + } + } diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java index 061f3584..63bb3747 100755 --- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -57,6 +57,7 @@ import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent; import org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner; import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; +import org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment; import static lombok.eclipse.EcjAugments.ASTNode_generatedBy; @@ -413,6 +414,16 @@ final class PatchFixesHider { } return result; } + + public static boolean isGenerated(org.eclipse.jdt.core.IMember member) { + boolean result = false; + try { + result = member.getNameRange().getLength() <= 0 || member.getNameRange().equals(member.getSourceRange()); + } catch (JavaModelException e) { + // better to assume it isn't generated + } + return result; + } public static boolean isBlockedVisitorAndGenerated(org.eclipse.jdt.core.dom.ASTNode node, org.eclipse.jdt.core.dom.ASTVisitor visitor) { if (visitor == null) return false; @@ -465,8 +476,10 @@ final class PatchFixesHider { StringBuilder signature = new StringBuilder(); addAnnotations(annotations, signature); - if ((Boolean)processor.getClass().getDeclaredField("fPublic").get(processor)) signature.append("public "); - if ((Boolean)processor.getClass().getDeclaredField("fAbstract").get(processor)) signature.append("abstract "); + try { + if ((Boolean)processor.getClass().getDeclaredField("fPublic").get(processor)) signature.append("public "); + if ((Boolean)processor.getClass().getDeclaredField("fAbstract").get(processor)) signature.append("abstract "); + } catch (Throwable t) { } signature .append(declaration.getReturnType2().toString()) @@ -512,7 +525,7 @@ final class PatchFixesHider { for (Object value : normalAnn.values()) values.add(value.toString()); } - signature.append("@").append(annotation.resolveTypeBinding().getQualifiedName()); + signature.append("@").append(annotation.getTypeName().getFullyQualifiedName()); if (!values.isEmpty()) { signature.append("("); boolean first = true; @@ -688,7 +701,7 @@ final class PatchFixesHider { public static IMethod[] removeGeneratedMethods(IMethod[] methods) throws Exception { List result = new ArrayList(); for (IMethod m : methods) { - if (m.getNameRange().getLength() > 0 && !m.getNameRange().equals(m.getSourceRange())) result.add(m); + if (!isGenerated(m)) result.add(m); } return result.size() == methods.length ? methods : result.toArray(new IMethod[0]); } @@ -791,5 +804,21 @@ final class PatchFixesHider { return replace; } + + public static String getRealNodeSource(String original, org.eclipse.jdt.internal.compiler.ast.ASTNode node) { + if (!isGenerated(node)) return original; + + return node.toString(); + } + + public static java.lang.String getRealNodeSource(java.lang.String original, org.eclipse.jdt.core.dom.ASTNode node) throws Exception { + if (!isGenerated(node)) return original; + + return node.toString(); + } + + public static boolean skipRewriteVisibility(IncomingMemberVisibilityAdjustment adjustment) { + return isGenerated(adjustment.getMember()); + } } } -- cgit From d3b763f9dab4a46e88ff10bc2132fb6f12fda639 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 26 Oct 2021 15:59:59 +0200 Subject: [changelog] adding a few of @Rawi01's quality-of-life improvements in eclipse as an entry in the changelog. --- doc/changelog.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog.markdown b/doc/changelog.markdown index cd8a4353..5c13e2e2 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -3,6 +3,7 @@ Lombok Changelog ### v1.18.24 "Edgy Guinea Pig" * FEATURE: Turning a field named `uShape` into a getter is tricky: `getUShape` or `getuShape`? The community is split on which style to use. Lombok does `getUShape`, but if you prefer the `getuShape` style, add to `lombok.config`: `lombok.accessors.capitalization = beanspec`. [Issue #2693](https://github.com/projectlombok/lombok/issues/2693) [Pull Request #2996](https://github.com/projectlombok/lombok/pull/2996). Thanks __@YonathanSherwin__! +* BUGFIX: Various save actions and refactor scripts in eclipse work better. [Issue #2995](https://github.com/projectlombok/lombok/issues/2995) [Issue #1309](https://github.com/projectlombok/lombok/issues/1309) [Issue #2985](https://github.com/projectlombok/lombok/issues/2985) [Issue #2509](https://github.com/projectlombok/lombok/issues/2509) ### v1.18.22 (October 6th, 2021) * PLATFORM: JDK17 support added. [Issue #2898](https://github.com/projectlombok/lombok/issues/2898). -- cgit