aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@tipit.to>2009-06-23 08:04:44 +0200
committerReinier Zwitserloot <reinier@tipit.to>2009-06-23 08:04:44 +0200
commit8bbdcec6fad6edf8f335f9e0c6899fddc56e07c1 (patch)
tree2f9c6d2c92f0723454eb8486e1a18dd178d0e885
parent6c82a3c780539825157f721fcfe1a8894e73b161 (diff)
downloadlombok-8bbdcec6fad6edf8f335f9e0c6899fddc56e07c1.tar.gz
lombok-8bbdcec6fad6edf8f335f9e0c6899fddc56e07c1.tar.bz2
lombok-8bbdcec6fad6edf8f335f9e0c6899fddc56e07c1.zip
Figured out that our previous act of just assigning TypeReference objects directly to other nodes (e.g. from a FieldDeclaration's type to a method argument) is NOT a good idea, as this screws up when
the TypeReference object represents a generic type (like 'T') - each instance of a generic type has a different resolution, but 1 TypeReference object can only hold 1 resolution. Thus, a copyType() method has been written, and the Handle* classes have been updated to use it. Also, generateEquals() is half-finished in HandleData.
-rw-r--r--src/lombok/eclipse/Eclipse.java93
-rw-r--r--src/lombok/eclipse/handlers/HandleData.java139
-rw-r--r--src/lombok/eclipse/handlers/HandleGetter.java4
-rw-r--r--src/lombok/eclipse/handlers/HandleSetter.java2
4 files changed, 193 insertions, 45 deletions
diff --git a/src/lombok/eclipse/Eclipse.java b/src/lombok/eclipse/Eclipse.java
index 8457e28a..e717e491 100644
--- a/src/lombok/eclipse/Eclipse.java
+++ b/src/lombok/eclipse/Eclipse.java
@@ -22,14 +22,22 @@ import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
+import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.Literal;
import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
+import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
+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.lookup.TypeIds;
import org.osgi.framework.Bundle;
@@ -76,6 +84,91 @@ public class Eclipse {
return sb.toString();
}
+ public static TypeParameter[] copyTypeParams(TypeParameter[] params) {
+ if ( params == null ) return null;
+ TypeParameter[] out = new TypeParameter[params.length];
+ int idx = 0;
+ for ( TypeParameter param : params ) {
+ TypeParameter o = new TypeParameter();
+ o.annotations = param.annotations;
+ o.bits = param.bits;
+ o.modifiers = param.modifiers;
+ o.name = param.name;
+ o.type = copyType(param.type);
+ if ( param.bounds != null ) {
+ TypeReference[] b = new TypeReference[param.bounds.length];
+ int idx2 = 0;
+ for ( TypeReference ref : param.bounds ) b[idx2++] = copyType(ref);
+ o.bounds = b;
+ }
+ out[idx++] = o;
+ }
+ return out;
+ }
+
+ public static TypeReference copyType(TypeReference ref) {
+ if ( ref instanceof QualifiedTypeReference ) {
+ QualifiedTypeReference iRef = (QualifiedTypeReference) ref;
+ return new QualifiedTypeReference(iRef.tokens, iRef.sourcePositions);
+ }
+
+ if ( ref instanceof ArrayQualifiedTypeReference ) {
+ ArrayQualifiedTypeReference iRef = (ArrayQualifiedTypeReference) ref;
+ return new ArrayQualifiedTypeReference(iRef.tokens, iRef.dimensions(), iRef.sourcePositions);
+ }
+
+ if ( ref instanceof ParameterizedQualifiedTypeReference ) {
+ ParameterizedQualifiedTypeReference iRef = (ParameterizedQualifiedTypeReference) ref;
+ TypeReference[][] args = null;
+ if ( iRef.typeArguments != null ) {
+ args = new TypeReference[iRef.typeArguments.length][];
+ int idx = 0;
+ for ( TypeReference[] inRefArray : iRef.typeArguments ) {
+ if ( inRefArray == null ) args[idx++] = null;
+ else {
+ TypeReference[] outRefArray = new TypeReference[inRefArray.length];
+ int idx2 = 0;
+ for ( TypeReference inRef : inRefArray ) {
+ outRefArray[idx2++] = copyType(inRef);
+ }
+ args[idx++] = outRefArray;
+ }
+ }
+ }
+ return new ParameterizedQualifiedTypeReference(iRef.tokens, args, iRef.dimensions(), iRef.sourcePositions);
+ }
+
+ if ( ref instanceof SingleTypeReference ) {
+ SingleTypeReference iRef = (SingleTypeReference) ref;
+ return new SingleTypeReference(iRef.token, (long)iRef.sourceStart << 32 | iRef.sourceEnd);
+ }
+
+ if ( ref instanceof ArrayTypeReference ) {
+ ArrayTypeReference iRef = (ArrayTypeReference) ref;
+ return new ArrayTypeReference(iRef.token, iRef.dimensions(), (long)iRef.sourceStart << 32 | iRef.sourceEnd);
+ }
+
+ if ( ref instanceof ParameterizedSingleTypeReference ) {
+ ParameterizedSingleTypeReference iRef = (ParameterizedSingleTypeReference) ref;
+ TypeReference[] args = null;
+ if ( iRef.typeArguments != null ) {
+ args = new TypeReference[iRef.typeArguments.length];
+ int idx = 0;
+ for ( TypeReference inRef : iRef.typeArguments ) {
+ if ( inRef == null ) args[idx++] = null;
+ else args[idx++] = copyType(inRef);
+ }
+ }
+ return new ParameterizedSingleTypeReference(iRef.token, args, iRef.dimensions(), (long)iRef.sourceStart << 32 | iRef.sourceEnd);
+ }
+
+ if ( ref instanceof Wildcard ) {
+ return new Wildcard(((Wildcard)ref).kind);
+ }
+
+ return ref;
+ }
+
public static boolean annotationTypeMatches(Class<? extends java.lang.annotation.Annotation> type, Node node) {
if ( node.getKind() != Kind.ANNOTATION ) return false;
TypeReference typeRef = ((Annotation)node.get()).type;
diff --git a/src/lombok/eclipse/handlers/HandleData.java b/src/lombok/eclipse/handlers/HandleData.java
index dd398d74..27757e7d 100644
--- a/src/lombok/eclipse/handlers/HandleData.java
+++ b/src/lombok/eclipse/handlers/HandleData.java
@@ -1,11 +1,11 @@
package lombok.eclipse.handlers;
+import static lombok.eclipse.Eclipse.*;
import static lombok.eclipse.handlers.PKG.*;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
import lombok.AccessLevel;
@@ -15,22 +15,28 @@ import lombok.core.AST.Kind;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseAST.Node;
+import lombok.eclipse.handlers.PKG.MethodExistsResult;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
-import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.Assignment;
import org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
+import org.eclipse.jdt.internal.compiler.ast.CastExpression;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
+import org.eclipse.jdt.internal.compiler.ast.IfStatement;
+import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
@@ -39,15 +45,12 @@ import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
+import org.eclipse.jdt.internal.compiler.ast.TrueLiteral;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
-import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
-import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
-import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
-import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
-import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.mangosdk.spi.ProviderFor;
@ProviderFor(EclipseAnnotationHandler.class)
@@ -81,42 +84,22 @@ public class HandleData implements EclipseAnnotationHandler<Data> {
new HandleSetter().generateSetterForField(child, annotationNode.get());
}
- switch ( methodExists("toString", typeNode) ) {
- case NOT_EXISTS:
+ if ( methodExists("toString", typeNode) == MethodExistsResult.NOT_EXISTS ) {
MethodDeclaration toString = createToString(typeNode, nodesForConstructorAndToString, ast);
injectMethod(typeNode, toString);
- //fallthrough
- case EXISTS_BY_LOMBOK:
-// TypeBinding javaLangString = null;
-// if ( typeDecl.scope != null ) javaLangString = typeDecl.scope.getJavaLangString();
-// fixMethodBinding(getExistingLombokMethod("toString", typeNode), javaLangString, Collections.<Node>emptyList());
}
- switch ( constructorExists(typeNode) ) {
- case NOT_EXISTS:
+ if ( constructorExists(typeNode) == MethodExistsResult.NOT_EXISTS ) {
ConstructorDeclaration constructor = createConstructor(
ann.staticConstructor().isEmpty(), typeNode, nodesForConstructorAndToString, ast);
injectMethod(typeNode, constructor);
- //fallthrough
- case EXISTS_BY_LOMBOK:
-// constructor = createConstructor(
-// ann.staticConstructor().isEmpty(), typeNode, nodesForConstructorAndToString, ast);
-// injectScopeIntoConstructor(constructor, nodesForConstructorAndToString, typeDecl);
-// fixMethodBinding(getExistingLombokConstructor(typeNode), typeDecl.binding, nodesForConstructorAndToString);
}
if ( !ann.staticConstructor().isEmpty() ) {
- switch ( methodExists("of", typeNode) ) {
- case NOT_EXISTS:
+ if ( methodExists("of", typeNode) == MethodExistsResult.NOT_EXISTS ) {
MethodDeclaration staticConstructor = createStaticConstructor(
ann.staticConstructor(), typeNode, nodesForConstructorAndToString, ast);
injectMethod(typeNode, staticConstructor);
- //fallthrough
- case EXISTS_BY_LOMBOK:
-// fixMethodBinding(getExistingLombokMethod(ann.staticConstructor(), typeNode), typeDecl.binding, nodesForConstructorAndToString);
-// injectScopeIntoStaticConstructor((MethodDeclaration) getExistingLombokMethod(
-// ann.staticConstructor(), typeNode).get(),
-// nodesForConstructorAndToString, typeDecl);
}
}
@@ -190,7 +173,7 @@ public class HandleData implements EclipseAnnotationHandler<Data> {
thisX.token = field.name;
assigns.add(new Assignment(thisX, new SingleNameReference(field.name, p), (int)p));
long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd;
- args.add(new Argument(field.name, fieldPos, field.type, 0));
+ args.add(new Argument(field.name, fieldPos, copyType(field.type), 0));
}
constructor.statements = assigns.toArray(new Statement[assigns.size()]);
@@ -209,7 +192,7 @@ public class HandleData implements EclipseAnnotationHandler<Data> {
constructor.annotations = null;
constructor.selector = name.toCharArray();
constructor.thrownExceptions = null;
- constructor.typeParameters = null;
+ constructor.typeParameters = copyTypeParams(((TypeDeclaration)type.get()).typeParameters);
constructor.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = pos.sourceStart;
constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = pos.sourceEnd;
@@ -217,13 +200,13 @@ public class HandleData implements EclipseAnnotationHandler<Data> {
List<Argument> args = new ArrayList<Argument>();
List<Expression> assigns = new ArrayList<Expression>();
AllocationExpression statement = new AllocationExpression();
- statement.type = constructor.returnType;
+ statement.type = copyType(constructor.returnType);
for ( Node fieldNode : fields ) {
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd;
assigns.add(new SingleNameReference(field.name, fieldPos));
- args.add(new Argument(field.name, fieldPos, field.type, 0));
+ args.add(new Argument(field.name, fieldPos, copyType(field.type), 0));
}
statement.arguments = assigns.toArray(new Expression[assigns.size()]);
@@ -232,14 +215,86 @@ public class HandleData implements EclipseAnnotationHandler<Data> {
return constructor;
}
- private MethodDeclaration createEquals(Collection<Node> fields) {
- //If using an of() constructor, make private.
- //method params
- //on loop: Assignment(FieldReference(ThisReference, "x"), SingleNameReference("x"))
- return null;
+ private MethodDeclaration createEquals(Node type, Collection<Node> fields, ASTNode pos) {
+ long p = (long)pos.sourceStart << 32 | pos.sourceEnd;
+ MethodDeclaration method = new MethodDeclaration(
+ ((CompilationUnitDeclaration) type.top().get()).compilationResult);
+
+ method.modifiers = PKG.toModifier(AccessLevel.PUBLIC);
+ method.returnType = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
+ method.annotations = null;
+ method.selector = "equals".toCharArray();
+ method.thrownExceptions = null;
+ method.typeParameters = null;
+ method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
+ method.bodyStart = method.declarationSourceStart = method.sourceStart = pos.sourceStart;
+ method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = pos.sourceEnd;
+ method.arguments = new Argument[] {
+ new Argument(new char[] { 'o' }, 0,
+ new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] { 0, 0, 0 }), 0)
+ };
+
+ List<Statement> statements = new ArrayList<Statement>();
+
+ /* if ( o == this ) return true; */ {
+ EqualExpression otherEqualsThis = new EqualExpression(
+ new SingleNameReference(new char[] { 'o' }, 0),
+ new ThisReference(0, 0), OperatorIds.EQUAL_EQUAL);
+
+ ReturnStatement returnTrue = new ReturnStatement(new TrueLiteral(0, 0), 0, 0);
+ IfStatement ifOtherEqualsThis = new IfStatement(otherEqualsThis, returnTrue, 0, 0);
+ statements.add(ifOtherEqualsThis);
+ }
+
+ /* if ( o == null ) return false; */ {
+ EqualExpression otherEqualsNull = new EqualExpression(
+ new SingleNameReference(new char[] { 'o' }, 0),
+ new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL);
+
+ ReturnStatement returnFalse = new ReturnStatement(new FalseLiteral(0, 0), 0, 0);
+ IfStatement ifOtherEqualsNull = new IfStatement(otherEqualsNull, returnFalse, 0, 0);
+ statements.add(ifOtherEqualsNull);
+ }
+
+ /* if ( o.getClass() != getClass() ) return false; */ {
+ MessageSend otherGetClass = new MessageSend();
+ otherGetClass.receiver = new SingleNameReference(new char[] { 'o' }, 0);
+ otherGetClass.selector = "getClass".toCharArray();
+ MessageSend thisGetClass = new MessageSend();
+ thisGetClass.receiver = new ThisReference(0, 0);
+ thisGetClass.selector = "getClass".toCharArray();
+ EqualExpression classesNotEqual = new EqualExpression(otherGetClass, thisGetClass, OperatorIds.NOT_EQUAL);
+ ReturnStatement returnFalse = new ReturnStatement(new FalseLiteral(0, 0), 0, 0);
+ IfStatement ifClassesNotEqual = new IfStatement(classesNotEqual, returnFalse, 0, 0);
+ statements.add(ifClassesNotEqual);
+ }
+
+ char[] otherN = "other".toCharArray();
+
+ //TODO fix generics raw type warnings by inserting Wildcards.
+ /* MyType other = (MyType) o; */ {
+ if ( !fields.isEmpty() ) {
+ LocalDeclaration other = new LocalDeclaration(otherN, 0, 0);
+ other.initialization = new CastExpression(
+ new SingleNameReference(new char[] { 'o' }, 0),
+ new SingleNameReference(((TypeDeclaration)type.get()).name, 0));
+ }
+ }
+
+ for ( Node field : fields ) {
+ FieldDeclaration f = (FieldDeclaration) field.get();
+ //compare if primitive, write per-primitive special code, otherwise use == null ? other == null ? .equals(other).
+ //TODO I LEFT IT HERE
+ }
+
+ /* return true; */ {
+ statements.add(new ReturnStatement(new TrueLiteral(0, 0), 0, 0));
+ }
+ method.statements = statements.toArray(new Statement[statements.size()]);
+ return method;
}
- private MethodDeclaration createHashCode(Collection<Node> fields) {
+ private MethodDeclaration createHashCode(Node type, Collection<Node> fields, ASTNode pos) {
//booleans: conditionalexpression that bounces between 1231 and 1237.
//longs: (int) (lng ^ (lng >>> 32));
//doubles and floats: Double.doubleToLongBits, then as long.
diff --git a/src/lombok/eclipse/handlers/HandleGetter.java b/src/lombok/eclipse/handlers/HandleGetter.java
index d0ec673d..b0353a34 100644
--- a/src/lombok/eclipse/handlers/HandleGetter.java
+++ b/src/lombok/eclipse/handlers/HandleGetter.java
@@ -59,7 +59,7 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
}
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
- TypeReference fieldType = field.type;
+ TypeReference fieldType = Eclipse.copyType(field.type);
String getterName = TransformationsUtil.toGetterName(
new String(field.name), nameEquals(fieldType.getTypeName(), "boolean"));
@@ -89,7 +89,7 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
int modifier, ASTNode pos) {
MethodDeclaration method = new MethodDeclaration(parent.compilationResult);
method.modifiers = modifier;
- method.returnType = field.type;
+ method.returnType = Eclipse.copyType(field.type);
method.annotations = null;
method.arguments = null;
method.selector = name.toCharArray();
diff --git a/src/lombok/eclipse/handlers/HandleSetter.java b/src/lombok/eclipse/handlers/HandleSetter.java
index d33594b1..2367d66d 100644
--- a/src/lombok/eclipse/handlers/HandleSetter.java
+++ b/src/lombok/eclipse/handlers/HandleSetter.java
@@ -95,7 +95,7 @@ public class HandleSetter implements EclipseAnnotationHandler<Setter> {
method.modifiers = modifier;
method.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0);
method.annotations = null;
- Argument param = new Argument(field.name, pos, field.type, 0);
+ Argument param = new Argument(field.name, pos, Eclipse.copyType(field.type), 0);
method.arguments = new Argument[] { param };
method.selector = name.toCharArray();
method.binding = null;