mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-14 06:17:44 +00:00
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.
This commit is contained in:
1 parent
6c82a3c780
commit
8bbdcec6fa
4 files changed
+193
-45
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user