aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@zwitserloot.com>2012-07-16 23:59:43 +0200
committerReinier Zwitserloot <reinier@zwitserloot.com>2012-07-17 00:15:40 +0200
commitdd18f63ee539a362fac2525c48d83ccff7a06dc9 (patch)
tree2f6a367e1134f82056a776aed6347ce59bc399bb
parenta382c21d464c22658e8c2eea7d7d75c2a6747527 (diff)
downloadlombok-dd18f63ee539a362fac2525c48d83ccff7a06dc9.tar.gz
lombok-dd18f63ee539a362fac2525c48d83ccff7a06dc9.tar.bz2
lombok-dd18f63ee539a362fac2525c48d83ccff7a06dc9.zip
Fix for issue 396: Static constructors generated for classes with type parameters did not work in javac.
-rw-r--r--src/core/lombok/javac/handlers/HandleConstructor.java13
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java74
-rw-r--r--test/transform/resource/after-delombok/Constructors.java14
-rw-r--r--test/transform/resource/after-ecj/Constructors.java11
-rw-r--r--test/transform/resource/before/Constructors.java4
5 files changed, 104 insertions, 12 deletions
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<JCExpression> 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<JCAnnotation> nonNulls = findAnnotations(fieldNode, TransformationsUtil.NON_NULL_PATTERN);
List<JCAnnotation> 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<JCExpression> 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<T extends Number> {
public static <T extends Number> RequiredArgsConstructorStaticNameGenerics<T> of(final T x) {
return new RequiredArgsConstructorStaticNameGenerics<T>(x);
}
+}
+class RequiredArgsConstructorStaticNameGenerics2<T extends Number> {
+ final Class<T> x;
+ String name;
+
+ @java.lang.SuppressWarnings("all")
+ private RequiredArgsConstructorStaticNameGenerics2(final Class<T> x) {
+ this.x = x;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public static <T extends Number> RequiredArgsConstructorStaticNameGenerics2<T> of(final Class<T> x) {
+ return new RequiredArgsConstructorStaticNameGenerics2<T>(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") <T extends Number>RequiredArgsConstructorStaticNameGenerics<T> of(final T x) {
return new RequiredArgsConstructorStaticNameGenerics<T>(x);
}
+}
+@lombok.RequiredArgsConstructor(staticName = "of") class RequiredArgsConstructorStaticNameGenerics2<T extends Number> {
+ final Class<T> x;
+ String name;
+ private @java.lang.SuppressWarnings("all") RequiredArgsConstructorStaticNameGenerics2(final Class<T> x) {
+ super();
+ this.x = x;
+ }
+ public static @java.lang.SuppressWarnings("all") <T extends Number>RequiredArgsConstructorStaticNameGenerics2<T> of(final Class<T> x) {
+ return new RequiredArgsConstructorStaticNameGenerics2<T>(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<T extends Number> {
+ final Class<T> x;
+ String name;
+}