From c09481eb8e1475c9495c6d5a59df7234803b2a95 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 16 Jul 2012 20:56:35 +0200 Subject: Added tests for @ExtensionMethod --- .../resource/before/ExtensionMethodPlain.java | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 test/transform/resource/before/ExtensionMethodPlain.java (limited to 'test/transform/resource/before') diff --git a/test/transform/resource/before/ExtensionMethodPlain.java b/test/transform/resource/before/ExtensionMethodPlain.java new file mode 100644 index 00000000..8c2f369d --- /dev/null +++ b/test/transform/resource/before/ExtensionMethodPlain.java @@ -0,0 +1,23 @@ +import lombok.experimental.ExtensionMethod; + +@ExtensionMethod({java.util.Arrays.class, ExtensionMethodPlain.Extensions.class}) +class ExtensionMethodPlain { + public String test() { + int[] intArray = {5, 3, 8, 2}; + intArray.sort(); + + String iAmNull = null; + return iAmNull.or("hELlO, WORlD!".toTitleCase()); + } + + static class Extensions { + public static T or(T obj, T ifNull) { + return obj != null ? obj : ifNull; + } + + public static String toTitleCase(String in) { + if (in.isEmpty()) return in; + return "" + Character.toTitleCase(in.charAt(0)) + in.substring(1).toLowerCase(); + } + } +} -- cgit From e6421509987c01e06b7c79ef406cc01ff174ae81 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 16 Jul 2012 22:04:39 +0200 Subject: Updated tests to reflect changes to delombok (delombok now kills super(), because attrib adds them even in places where that's wrong). Also split up the SynchronizedName test into separate cases for each expected failure mode. --- src/delombok/lombok/delombok/PrettyCommentsPrinter.java | 11 ++++++++++- test/transform/resource/after-delombok/DataPlain.java | 1 - test/transform/resource/after-delombok/SneakyThrowsPlain.java | 1 - test/transform/resource/after-delombok/SynchronizedName.java | 11 ++--------- .../resource/after-delombok/SynchronizedNameNoSuchField.java | 7 +++++++ .../after-delombok/SynchronizedNameStaticToInstanceRef.java | 9 +++++++++ test/transform/resource/before/SynchronizedName.java | 6 ------ .../resource/before/SynchronizedNameNoSuchField.java | 8 ++++++++ .../resource/before/SynchronizedNameStaticToInstanceRef.java | 8 ++++++++ .../resource/messages-delombok/SynchronizedName.java.messages | 1 - .../SynchronizedNameNoSuchField.java.messages | 1 + .../SynchronizedNameStaticToInstanceRef.java.messages | 1 + .../SynchronizedNameStaticToInstanceRef.java.messages | 1 + .../resource/messages-idempotent/ValErrors.java.messages | 7 +++++++ 14 files changed, 54 insertions(+), 19 deletions(-) create mode 100644 test/transform/resource/after-delombok/SynchronizedNameNoSuchField.java create mode 100644 test/transform/resource/after-delombok/SynchronizedNameStaticToInstanceRef.java create mode 100644 test/transform/resource/before/SynchronizedNameNoSuchField.java create mode 100644 test/transform/resource/before/SynchronizedNameStaticToInstanceRef.java delete mode 100644 test/transform/resource/messages-delombok/SynchronizedName.java.messages create mode 100644 test/transform/resource/messages-delombok/SynchronizedNameNoSuchField.java.messages create mode 100644 test/transform/resource/messages-delombok/SynchronizedNameStaticToInstanceRef.java.messages create mode 100644 test/transform/resource/messages-idempotent/SynchronizedNameStaticToInstanceRef.java.messages create mode 100644 test/transform/resource/messages-idempotent/ValErrors.java.messages (limited to 'test/transform/resource/before') diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index 095928ad..2f47ccf6 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -1037,8 +1037,17 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { throw new UncheckedIOException(e); } } - + + private boolean isNoArgsSuperCall(JCExpression expr) { + if (!(expr instanceof JCMethodInvocation)) return false; + JCMethodInvocation tree = (JCMethodInvocation) expr; + if (!tree.typeargs.isEmpty() || !tree.args.isEmpty()) return false; + if (!(tree.meth instanceof JCIdent)) return false; + return ((JCIdent) tree.meth).name.toString().equals("super"); + } + public void visitExec(JCExpressionStatement tree) { + if (isNoArgsSuperCall(tree.expr)) return; try { printExpr(tree.expr); if (prec == TreeInfo.notExpression) print(";"); diff --git a/test/transform/resource/after-delombok/DataPlain.java b/test/transform/resource/after-delombok/DataPlain.java index cb002e07..a8cb37af 100644 --- a/test/transform/resource/after-delombok/DataPlain.java +++ b/test/transform/resource/after-delombok/DataPlain.java @@ -155,7 +155,6 @@ final class Data3 { final class Data4 extends java.util.Timer { int x; Data4() { - super(); } @java.lang.SuppressWarnings("all") public int getX() { diff --git a/test/transform/resource/after-delombok/SneakyThrowsPlain.java b/test/transform/resource/after-delombok/SneakyThrowsPlain.java index 5c0890b5..f712ab55 100644 --- a/test/transform/resource/after-delombok/SneakyThrowsPlain.java +++ b/test/transform/resource/after-delombok/SneakyThrowsPlain.java @@ -1,6 +1,5 @@ class SneakyThrowsPlain { SneakyThrowsPlain() { - super(); try { System.out.println("constructor"); } catch (final java.lang.Throwable $ex) { diff --git a/test/transform/resource/after-delombok/SynchronizedName.java b/test/transform/resource/after-delombok/SynchronizedName.java index e7dd23ff..ab3c0431 100644 --- a/test/transform/resource/after-delombok/SynchronizedName.java +++ b/test/transform/resource/after-delombok/SynchronizedName.java @@ -1,19 +1,12 @@ class SynchronizedName { private Object read = new Object(); private static Object READ = new Object(); + void test1() { synchronized (this.read) { System.out.println("one"); } } - void test2() { - System.out.println("two"); - } - static void test3() { - synchronized (SynchronizedName.read) { - System.out.println("three"); - } - } void test4() { synchronized (this.READ) { System.out.println("four"); @@ -24,4 +17,4 @@ class SynchronizedName { System.out.println("five"); } } -} +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/SynchronizedNameNoSuchField.java b/test/transform/resource/after-delombok/SynchronizedNameNoSuchField.java new file mode 100644 index 00000000..d252985f --- /dev/null +++ b/test/transform/resource/after-delombok/SynchronizedNameNoSuchField.java @@ -0,0 +1,7 @@ +class SynchronizedNameNoSuchField { + private Object read = new Object(); + private static Object READ = new Object(); + void test2() { + System.out.println("two"); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/SynchronizedNameStaticToInstanceRef.java b/test/transform/resource/after-delombok/SynchronizedNameStaticToInstanceRef.java new file mode 100644 index 00000000..8441570b --- /dev/null +++ b/test/transform/resource/after-delombok/SynchronizedNameStaticToInstanceRef.java @@ -0,0 +1,9 @@ +class SynchronizedNameStaticToInstanceRef { + private Object read = new Object(); + private static Object READ = new Object(); + static void test3() { + synchronized (SynchronizedNameStaticToInstanceRef.read) { + System.out.println("three"); + } + } +} \ No newline at end of file diff --git a/test/transform/resource/before/SynchronizedName.java b/test/transform/resource/before/SynchronizedName.java index 5d074113..7553a8ce 100644 --- a/test/transform/resource/before/SynchronizedName.java +++ b/test/transform/resource/before/SynchronizedName.java @@ -5,12 +5,6 @@ class SynchronizedName { @lombok.Synchronized("read") void test1() { System.out.println("one"); } - @lombok.Synchronized("write") void test2() { - System.out.println("two"); - } - @lombok.Synchronized("read") static void test3() { - System.out.println("three"); - } @lombok.Synchronized("READ") void test4() { System.out.println("four"); } diff --git a/test/transform/resource/before/SynchronizedNameNoSuchField.java b/test/transform/resource/before/SynchronizedNameNoSuchField.java new file mode 100644 index 00000000..343ba6ae --- /dev/null +++ b/test/transform/resource/before/SynchronizedNameNoSuchField.java @@ -0,0 +1,8 @@ +class SynchronizedNameNoSuchField { + private Object read = new Object(); + private static Object READ = new Object(); + + @lombok.Synchronized("write") void test2() { + System.out.println("two"); + } +} diff --git a/test/transform/resource/before/SynchronizedNameStaticToInstanceRef.java b/test/transform/resource/before/SynchronizedNameStaticToInstanceRef.java new file mode 100644 index 00000000..08f9dbf1 --- /dev/null +++ b/test/transform/resource/before/SynchronizedNameStaticToInstanceRef.java @@ -0,0 +1,8 @@ +class SynchronizedNameStaticToInstanceRef { + private Object read = new Object(); + private static Object READ = new Object(); + + @lombok.Synchronized("read") static void test3() { + System.out.println("three"); + } +} diff --git a/test/transform/resource/messages-delombok/SynchronizedName.java.messages b/test/transform/resource/messages-delombok/SynchronizedName.java.messages deleted file mode 100644 index 2af3ca1d..00000000 --- a/test/transform/resource/messages-delombok/SynchronizedName.java.messages +++ /dev/null @@ -1 +0,0 @@ -8:9 ERROR The field write does not exist. \ No newline at end of file diff --git a/test/transform/resource/messages-delombok/SynchronizedNameNoSuchField.java.messages b/test/transform/resource/messages-delombok/SynchronizedNameNoSuchField.java.messages new file mode 100644 index 00000000..bffd29e6 --- /dev/null +++ b/test/transform/resource/messages-delombok/SynchronizedNameNoSuchField.java.messages @@ -0,0 +1 @@ +5:9 ERROR The field write does not exist. diff --git a/test/transform/resource/messages-delombok/SynchronizedNameStaticToInstanceRef.java.messages b/test/transform/resource/messages-delombok/SynchronizedNameStaticToInstanceRef.java.messages new file mode 100644 index 00000000..1a084653 --- /dev/null +++ b/test/transform/resource/messages-delombok/SynchronizedNameStaticToInstanceRef.java.messages @@ -0,0 +1 @@ +-1:-1 ERROR non-static variable read cannot be referenced from a static context diff --git a/test/transform/resource/messages-idempotent/SynchronizedNameStaticToInstanceRef.java.messages b/test/transform/resource/messages-idempotent/SynchronizedNameStaticToInstanceRef.java.messages new file mode 100644 index 00000000..c34e29f6 --- /dev/null +++ b/test/transform/resource/messages-idempotent/SynchronizedNameStaticToInstanceRef.java.messages @@ -0,0 +1 @@ +5:66 ERROR non-static variable read cannot be referenced from a static context diff --git a/test/transform/resource/messages-idempotent/ValErrors.java.messages b/test/transform/resource/messages-idempotent/ValErrors.java.messages new file mode 100644 index 00000000..6f666511 --- /dev/null +++ b/test/transform/resource/messages-idempotent/ValErrors.java.messages @@ -0,0 +1,7 @@ +3:44 ERROR cannot find symbol +symbol : variable d +location: class ValErrors +6:17 ERROR cannot find symbol +symbol : class val +location: class ValErrors +6:25 ERROR illegal initializer for -- cgit From a382c21d464c22658e8c2eea7d7d75c2a6747527 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 16 Jul 2012 23:18:58 +0200 Subject: fixed issue 391: Using 'staticConstructor' on @Data whilst an @XxxArgsConstructor is present means it gets ignored, but until now lombok didn't warn you about this. --- .../lombok/eclipse/handlers/HandleConstructor.java | 15 ++++++++--- .../lombok/javac/handlers/HandleConstructor.java | 15 ++++++++--- .../ConflictingStaticConstructorNames.java | 29 ++++++++++++++++++++++ .../ConflictingStaticConstructorNames.java | 25 +++++++++++++++++++ .../before/ConflictingStaticConstructorNames.java | 4 +++ ...ConflictingStaticConstructorNames.java.messages | 1 + ...ConflictingStaticConstructorNames.java.messages | 1 + 7 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 test/transform/resource/after-delombok/ConflictingStaticConstructorNames.java create mode 100644 test/transform/resource/after-ecj/ConflictingStaticConstructorNames.java create mode 100644 test/transform/resource/before/ConflictingStaticConstructorNames.java create mode 100644 test/transform/resource/messages-delombok/ConflictingStaticConstructorNames.java.messages create mode 100644 test/transform/resource/messages-ecj/ConflictingStaticConstructorNames.java.messages (limited to 'test/transform/resource/before') diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index eec41577..25d47870 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -156,20 +156,29 @@ public class HandleConstructor { } public void generateConstructor(EclipseNode typeNode, AccessLevel level, List fields, String staticName, boolean skipIfConstructorExists, boolean suppressConstructorProperties, ASTNode source) { + boolean staticConstrRequired = staticName != null && !staticName.equals(""); + if (skipIfConstructorExists && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return; if (skipIfConstructorExists) { for (EclipseNode child : typeNode.down()) { if (child.getKind() == Kind.ANNOTATION) { if (annotationTypeMatches(NoArgsConstructor.class, child) || annotationTypeMatches(AllArgsConstructor.class, child) || - annotationTypeMatches(RequiredArgsConstructor.class, child)) + annotationTypeMatches(RequiredArgsConstructor.class, child)) { + + if (staticConstrRequired) { + // @Data has asked us to generate a constructor, but we're going to skip this instruction, as an explicit 'make a constructor' annotation + // will take care of it. However, @Data also wants a specific static name; this will be ignored; the appropriate way to do this is to use + // the 'staticName' parameter of the @XArgsConstructor you've stuck on your type. + // We should warn that we're ignoring @Data's 'staticConstructor' param. + typeNode.addWarning("Ignoring static constructor name: explicit @XxxArgsConstructor annotation present; its `staticName` parameter will be used.", source.sourceStart, source.sourceEnd); + } return; + } } } } - boolean staticConstrRequired = staticName != null && !staticName.equals(""); - ConstructorDeclaration constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, suppressConstructorProperties, source); injectMethod(typeNode, constr); if (staticConstrRequired) { diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index a2463728..65ad2547 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -154,20 +154,29 @@ public class HandleConstructor { } public void generateConstructor(JavacNode typeNode, AccessLevel level, List fields, String staticName, boolean skipIfConstructorExists, boolean suppressConstructorProperties, JavacNode source) { + boolean staticConstrRequired = staticName != null && !staticName.equals(""); + if (skipIfConstructorExists && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return; if (skipIfConstructorExists) { for (JavacNode child : typeNode.down()) { if (child.getKind() == Kind.ANNOTATION) { if (annotationTypeMatches(NoArgsConstructor.class, child) || annotationTypeMatches(AllArgsConstructor.class, child) || - annotationTypeMatches(RequiredArgsConstructor.class, child)) + annotationTypeMatches(RequiredArgsConstructor.class, child)) { + + if (staticConstrRequired) { + // @Data has asked us to generate a constructor, but we're going to skip this instruction, as an explicit 'make a constructor' annotation + // will take care of it. However, @Data also wants a specific static name; this will be ignored; the appropriate way to do this is to use + // the 'staticName' parameter of the @XArgsConstructor you've stuck on your type. + // We should warn that we're ignoring @Data's 'staticConstructor' param. + source.addWarning("Ignoring static constructor name: explicit @XxxArgsConstructor annotation present; its `staticName` parameter will be used."); + } return; + } } } } - boolean staticConstrRequired = staticName != null && !staticName.equals(""); - JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, suppressConstructorProperties, source.get()); injectMethod(typeNode, constr); if (staticConstrRequired) { diff --git a/test/transform/resource/after-delombok/ConflictingStaticConstructorNames.java b/test/transform/resource/after-delombok/ConflictingStaticConstructorNames.java new file mode 100644 index 00000000..172ed298 --- /dev/null +++ b/test/transform/resource/after-delombok/ConflictingStaticConstructorNames.java @@ -0,0 +1,29 @@ +class ConflictingStaticConstructorNames { + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof ConflictingStaticConstructorNames)) return false; + final ConflictingStaticConstructorNames other = (ConflictingStaticConstructorNames)o; + if (!other.canEqual((java.lang.Object)this)) return false; + return true; + } + @java.lang.SuppressWarnings("all") + public boolean canEqual(final java.lang.Object other) { + return other instanceof ConflictingStaticConstructorNames; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + int result = 1; + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "ConflictingStaticConstructorNames()"; + } + @java.lang.SuppressWarnings("all") + public ConflictingStaticConstructorNames() { + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/ConflictingStaticConstructorNames.java b/test/transform/resource/after-ecj/ConflictingStaticConstructorNames.java new file mode 100644 index 00000000..8da11258 --- /dev/null +++ b/test/transform/resource/after-ecj/ConflictingStaticConstructorNames.java @@ -0,0 +1,25 @@ +@lombok.Data(staticConstructor = "of") @lombok.NoArgsConstructor class ConflictingStaticConstructorNames { + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof ConflictingStaticConstructorNames))) + return false; + final @java.lang.SuppressWarnings("all") ConflictingStaticConstructorNames other = (ConflictingStaticConstructorNames) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + return true; + } + public @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof ConflictingStaticConstructorNames); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + int result = 1; + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return "ConflictingStaticConstructorNames()"; + } + public @java.lang.SuppressWarnings("all") ConflictingStaticConstructorNames() { + super(); + } +} \ No newline at end of file diff --git a/test/transform/resource/before/ConflictingStaticConstructorNames.java b/test/transform/resource/before/ConflictingStaticConstructorNames.java new file mode 100644 index 00000000..494e3cd6 --- /dev/null +++ b/test/transform/resource/before/ConflictingStaticConstructorNames.java @@ -0,0 +1,4 @@ +@lombok.Data(staticConstructor="of") +@lombok.NoArgsConstructor +class ConflictingStaticConstructorNames { +} \ No newline at end of file diff --git a/test/transform/resource/messages-delombok/ConflictingStaticConstructorNames.java.messages b/test/transform/resource/messages-delombok/ConflictingStaticConstructorNames.java.messages new file mode 100644 index 00000000..40366cd7 --- /dev/null +++ b/test/transform/resource/messages-delombok/ConflictingStaticConstructorNames.java.messages @@ -0,0 +1 @@ +1:1 WARNING Ignoring static constructor name: explicit @XxxArgsConstructor annotation present; its `staticName` parameter will be used. diff --git a/test/transform/resource/messages-ecj/ConflictingStaticConstructorNames.java.messages b/test/transform/resource/messages-ecj/ConflictingStaticConstructorNames.java.messages new file mode 100644 index 00000000..ecbf4a61 --- /dev/null +++ b/test/transform/resource/messages-ecj/ConflictingStaticConstructorNames.java.messages @@ -0,0 +1 @@ +1 warning Ignoring static constructor name: explicit @XxxArgsConstructor annotation present; its `staticName` parameter will be used. -- cgit From dd18f63ee539a362fac2525c48d83ccff7a06dc9 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 16 Jul 2012 23:59:43 +0200 Subject: Fix for issue 396: Static constructors generated for classes with type parameters did not work in javac. --- .../lombok/javac/handlers/HandleConstructor.java | 13 +--- .../lombok/javac/handlers/JavacHandlerUtil.java | 74 ++++++++++++++++++++++ .../resource/after-delombok/Constructors.java | 14 ++++ .../transform/resource/after-ecj/Constructors.java | 11 ++++ test/transform/resource/before/Constructors.java | 4 ++ 5 files changed, 104 insertions(+), 12 deletions(-) (limited to 'test/transform/resource/before') diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index 65ad2547..d701b41e 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -43,12 +43,10 @@ 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.JCFieldAccess; -import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCModifiers; import com.sun.tools.javac.tree.JCTree.JCReturn; import com.sun.tools.javac.tree.JCTree.JCStatement; -import com.sun.tools.javac.tree.JCTree.JCTypeApply; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; @@ -268,16 +266,7 @@ public class HandleConstructor { for (JavacNode fieldNode : fields) { JCVariableDecl field = (JCVariableDecl) fieldNode.get(); - JCExpression pType; - if (field.vartype instanceof JCIdent) pType = maker.Ident(((JCIdent)field.vartype).name); - else if (field.vartype instanceof JCTypeApply) { - JCTypeApply typeApply = (JCTypeApply) field.vartype; - ListBuffer tArgs = ListBuffer.lb(); - for (JCExpression arg : typeApply.arguments) tArgs.append(arg); - pType = maker.TypeApply(typeApply.clazz, tArgs.toList()); - } else { - pType = field.vartype; - } + JCExpression pType = cloneType(maker, field.vartype, source); List nonNulls = findAnnotations(fieldNode, TransformationsUtil.NON_NULL_PATTERN); List nullables = findAnnotations(fieldNode, TransformationsUtil.NULLABLE_PATTERN); JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.FINAL, nonNulls.appendList(nullables)), field.name, pType, null); diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index d2905101..ce7421b1 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -45,14 +45,17 @@ import lombok.experimental.Accessors; import lombok.javac.Javac; import lombok.javac.JavacNode; +import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.TypeTags; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; import com.sun.tools.javac.tree.JCTree.JCAssign; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCImport; import com.sun.tools.javac.tree.JCTree.JCLiteral; @@ -60,8 +63,12 @@ import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCModifiers; import com.sun.tools.javac.tree.JCTree.JCNewArray; +import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree; import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCTypeApply; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.JCTree.JCWildcard; +import com.sun.tools.javac.tree.JCTree.TypeBoundKind; import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @@ -920,4 +927,71 @@ public class JavacHandlerUtil { return node; } + + /** + * Creates a full clone of a given javac AST type node. Every part is cloned (every identifier, every select, every wildcard, every type apply). + * + * If there's any node in the tree that we don't know how to clone, that part isn't cloned. However, we wouldn't know what could possibly show up that we + * can't currently clone; that's just a safeguard. + * + * This should be used if the type looks the same in the code, but resolves differently. For example, a static method that has some generics in it named after + * the class's own parameter, but as its a static method, the static method's notion of {@code T} is different from the class notion of {@code T}. If you're duplicating + * a type used in the class context, you need to use this method. + */ + public static JCExpression cloneType(TreeMaker maker, JCExpression in, JCTree source) { + JCExpression out = cloneType0(maker, in); + if (out != null) recursiveSetGeneratedBy(out, source); + return out; + } + + private static JCExpression cloneType0(TreeMaker maker, JCTree in) { + if (in == null) return null; + + if (in instanceof JCPrimitiveTypeTree) return (JCExpression) in; + + if (in instanceof JCIdent) { + return maker.Ident(((JCIdent) in).name); + } + + if (in instanceof JCFieldAccess) { + JCFieldAccess fa = (JCFieldAccess) in; + return maker.Select(cloneType0(maker, fa.selected), fa.name); + } + + if (in instanceof JCArrayTypeTree) { + JCArrayTypeTree att = (JCArrayTypeTree) in; + return maker.TypeArray(cloneType0(maker, att.elemtype)); + } + + if (in instanceof JCTypeApply) { + JCTypeApply ta = (JCTypeApply) in; + ListBuffer lb = ListBuffer.lb(); + for (JCExpression typeArg : ta.arguments) { + lb.append(cloneType0(maker, typeArg)); + } + return maker.TypeApply(cloneType0(maker, ta.clazz), lb.toList()); + } + + if (in instanceof JCWildcard) { + JCWildcard w = (JCWildcard) in; + JCExpression newInner = cloneType0(maker, w.inner); + TypeBoundKind newKind; + switch (w.getKind()) { + case SUPER_WILDCARD: + newKind = maker.TypeBoundKind(BoundKind.SUPER); + break; + case EXTENDS_WILDCARD: + newKind = maker.TypeBoundKind(BoundKind.EXTENDS); + break; + default: + case UNBOUNDED_WILDCARD: + newKind = maker.TypeBoundKind(BoundKind.UNBOUND); + break; + } + return maker.Wildcard(newKind, newInner); + } + + // This is somewhat unsafe, but it's better than outright throwing an exception here. Returning null will just cause an exception down the pipeline. + return (JCExpression) in; + } } diff --git a/test/transform/resource/after-delombok/Constructors.java b/test/transform/resource/after-delombok/Constructors.java index db48b6b8..d4633dbc 100644 --- a/test/transform/resource/after-delombok/Constructors.java +++ b/test/transform/resource/after-delombok/Constructors.java @@ -58,4 +58,18 @@ class RequiredArgsConstructorStaticNameGenerics { public static RequiredArgsConstructorStaticNameGenerics of(final T x) { return new RequiredArgsConstructorStaticNameGenerics(x); } +} +class RequiredArgsConstructorStaticNameGenerics2 { + final Class x; + String name; + + @java.lang.SuppressWarnings("all") + private RequiredArgsConstructorStaticNameGenerics2(final Class x) { + this.x = x; + } + + @java.lang.SuppressWarnings("all") + public static RequiredArgsConstructorStaticNameGenerics2 of(final Class x) { + return new RequiredArgsConstructorStaticNameGenerics2(x); + } } \ No newline at end of file diff --git a/test/transform/resource/after-ecj/Constructors.java b/test/transform/resource/after-ecj/Constructors.java index e6dd8a21..e994702f 100644 --- a/test/transform/resource/after-ecj/Constructors.java +++ b/test/transform/resource/after-ecj/Constructors.java @@ -51,4 +51,15 @@ public static @java.lang.SuppressWarnings("all") RequiredArgsConstructorStaticNameGenerics of(final T x) { return new RequiredArgsConstructorStaticNameGenerics(x); } +} +@lombok.RequiredArgsConstructor(staticName = "of") class RequiredArgsConstructorStaticNameGenerics2 { + final Class x; + String name; + private @java.lang.SuppressWarnings("all") RequiredArgsConstructorStaticNameGenerics2(final Class x) { + super(); + this.x = x; + } + public static @java.lang.SuppressWarnings("all") RequiredArgsConstructorStaticNameGenerics2 of(final Class x) { + return new RequiredArgsConstructorStaticNameGenerics2(x); + } } \ No newline at end of file diff --git a/test/transform/resource/before/Constructors.java b/test/transform/resource/before/Constructors.java index 272fa850..d3ed3504 100644 --- a/test/transform/resource/before/Constructors.java +++ b/test/transform/resource/before/Constructors.java @@ -22,3 +22,7 @@ final T x; String name; } +@lombok.RequiredArgsConstructor(staticName="of") class RequiredArgsConstructorStaticNameGenerics2 { + final Class x; + String name; +} -- cgit