Fix for issue 396: Static constructors generated for classes with type parameters did not work in javac.

This commit is contained in:
Reinier Zwitserloot
2012-07-17 00:15:40 +02:00
parent a382c21d46
commit dd18f63ee5
5 changed files with 104 additions and 12 deletions
@@ -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);
@@ -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;
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -22,3 +22,7 @@
final T x;
String name;
}
@lombok.RequiredArgsConstructor(staticName="of") class RequiredArgsConstructorStaticNameGenerics2<T extends Number> {
final Class<T> x;
String name;
}