diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java | 202 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java | 1 |
2 files changed, 141 insertions, 62 deletions
diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index e501c3f1..ed13fd1b 100644 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -47,6 +47,7 @@ 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.IfStatement; +import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression; import org.eclipse.jdt.internal.compiler.ast.IntLiteral; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.MessageSend; @@ -202,9 +203,13 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA } } + boolean needsCanEqual = false; switch (methodExists("equals", typeNode)) { case NOT_EXISTS: - MethodDeclaration equals = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), useFieldsDirectly); + boolean isFinal = (typeDecl.modifiers & ClassFileConstants.AccFinal) != 0; + needsCanEqual = !isDirectDescendantOfObject || !isFinal; + + MethodDeclaration equals = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), useFieldsDirectly, needsCanEqual); injectMethod(typeNode, equals); break; case EXISTS_BY_LOMBOK: @@ -217,6 +222,19 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA break; } + if (needsCanEqual) { + switch (methodExists("canEqual", typeNode)) { + case NOT_EXISTS: + MethodDeclaration equals = createCanEqual(typeNode, errorNode.get()); + injectMethod(typeNode, equals); + break; + case EXISTS_BY_LOMBOK: + case EXISTS_BY_USER: + default: + break; + } + } + switch (methodExists("hashCode", typeNode)) { case NOT_EXISTS: MethodDeclaration hashCode = createHashCode(typeNode, nodesForEquality, callSuper, errorNode.get(), useFieldsDirectly); @@ -415,9 +433,10 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA return method; } - private MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, boolean useFieldsDirectly) { + private MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, boolean useFieldsDirectly, boolean needsCanEqual) { int pS = source.sourceStart; int pE = source.sourceEnd; long p = (long)pS << 32 | pE; + TypeDeclaration typeDecl = (TypeDeclaration)type.get(); MethodDeclaration method = new MethodDeclaration( ((CompilationUnitDeclaration) type.top().get()).compilationResult); @@ -458,75 +477,36 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA statements.add(ifOtherEqualsThis); } - /* if (o == null) return false; */ { + /* if (!(o instanceof MyType) return false; */ { SingleNameReference oRef = new SingleNameReference(new char[] { 'o' }, p); Eclipse.setGeneratedBy(oRef, source); - NullLiteral nullLiteral = new NullLiteral(pS, pE); - Eclipse.setGeneratedBy(nullLiteral, source); - EqualExpression otherEqualsNull = new EqualExpression(oRef, nullLiteral, OperatorIds.EQUAL_EQUAL); - Eclipse.setGeneratedBy(otherEqualsNull, source); + + SingleTypeReference typeReference = new SingleTypeReference(typeDecl.name, p); + Eclipse.setGeneratedBy(typeReference, source); + + InstanceOfExpression instanceOf = new InstanceOfExpression(oRef, typeReference); + instanceOf.sourceStart = pS; instanceOf.sourceEnd = pE; + Eclipse.setGeneratedBy(instanceOf, source); + + Expression notInstanceOf = new UnaryExpression(instanceOf, OperatorIds.NOT); + Eclipse.setGeneratedBy(notInstanceOf, source); FalseLiteral falseLiteral = new FalseLiteral(pS, pE); Eclipse.setGeneratedBy(falseLiteral, source); + ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); Eclipse.setGeneratedBy(returnFalse, source); - IfStatement ifOtherEqualsNull = new IfStatement(otherEqualsNull, returnFalse, pS, pE); - Eclipse.setGeneratedBy(ifOtherEqualsNull, source); - statements.add(ifOtherEqualsNull); - } - - /* if (o.getClass() != getClass()) return false; */ { - MessageSend otherGetClass = new MessageSend(); - otherGetClass.sourceStart = pS; otherGetClass.sourceEnd = pE; - Eclipse.setGeneratedBy(otherGetClass, source); - otherGetClass.receiver = new SingleNameReference(new char[] { 'o' }, p); - Eclipse.setGeneratedBy(otherGetClass.receiver, source); - otherGetClass.selector = "getClass".toCharArray(); - MessageSend thisGetClass = new MessageSend(); - thisGetClass.sourceStart = pS; thisGetClass.sourceEnd = pE; - Eclipse.setGeneratedBy(thisGetClass, source); - thisGetClass.receiver = new ThisReference(pS, pE); - Eclipse.setGeneratedBy(thisGetClass.receiver, source); - thisGetClass.selector = "getClass".toCharArray(); - EqualExpression classesNotEqual = new EqualExpression(otherGetClass, thisGetClass, OperatorIds.NOT_EQUAL); - Eclipse.setGeneratedBy(classesNotEqual, source); - FalseLiteral falseLiteral = new FalseLiteral(pS, pE); - Eclipse.setGeneratedBy(falseLiteral, source); - ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); - Eclipse.setGeneratedBy(returnFalse, source); - IfStatement ifClassesNotEqual = new IfStatement(classesNotEqual, returnFalse, pS, pE); - Eclipse.setGeneratedBy(ifClassesNotEqual, source); - statements.add(ifClassesNotEqual); + + IfStatement ifNotInstanceOf = new IfStatement(notInstanceOf, returnFalse, pS, pE); + Eclipse.setGeneratedBy(ifNotInstanceOf, source); + statements.add(ifNotInstanceOf); } - char[] otherN = "other".toCharArray(); - - /* if (!super.equals(o)) return false; */ - if (callSuper) { - MessageSend callToSuper = new MessageSend(); - callToSuper.sourceStart = pS; callToSuper.sourceEnd = pE; - Eclipse.setGeneratedBy(callToSuper, source); - callToSuper.receiver = new SuperReference(pS, pE); - Eclipse.setGeneratedBy(callToSuper.receiver, source); - callToSuper.selector = "equals".toCharArray(); - SingleNameReference oRef = new SingleNameReference(new char[] { 'o' }, p); - Eclipse.setGeneratedBy(oRef, source); - callToSuper.arguments = new Expression[] {oRef}; - Expression superNotEqual = new UnaryExpression(callToSuper, OperatorIds.NOT); - Eclipse.setGeneratedBy(superNotEqual, source); - FalseLiteral falseLiteral = new FalseLiteral(pS, pE); - Eclipse.setGeneratedBy(falseLiteral, source); - ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); - Eclipse.setGeneratedBy(returnFalse, source); - IfStatement ifSuperEquals = new IfStatement(superNotEqual, returnFalse, pS, pE); - Eclipse.setGeneratedBy(ifSuperEquals, source); - statements.add(ifSuperEquals); - } + char[] otherName = "other".toCharArray(); - TypeDeclaration typeDecl = (TypeDeclaration)type.get(); /* MyType<?> other = (MyType<?>) o; */ { if (!fields.isEmpty()) { - LocalDeclaration other = new LocalDeclaration(otherN, pS, pE); + LocalDeclaration other = new LocalDeclaration(otherName, pS, pE); other.modifiers |= ClassFileConstants.AccFinal; Eclipse.setGeneratedBy(other, source); char[] typeName = typeDecl.name; @@ -556,11 +536,63 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA } } + /* if (!other.canEqual(this)) return false; */ { + if (needsCanEqual) { + MessageSend otherCanEqual = new MessageSend(); + otherCanEqual.sourceStart = pS; otherCanEqual.sourceEnd = pE; + Eclipse.setGeneratedBy(otherCanEqual, source); + otherCanEqual.receiver = new SingleNameReference(otherName, p); + Eclipse.setGeneratedBy(otherCanEqual.receiver, source); + otherCanEqual.selector = "canEqual".toCharArray(); + + ThisReference thisReference = new ThisReference(pS, pE); + Eclipse.setGeneratedBy(thisReference, source); + + otherCanEqual.arguments = new Expression[] {thisReference}; + + Expression notOtherCanEqual = new UnaryExpression(otherCanEqual, OperatorIds.NOT); + Eclipse.setGeneratedBy(notOtherCanEqual, source); + + FalseLiteral falseLiteral = new FalseLiteral(pS, pE); + Eclipse.setGeneratedBy(falseLiteral, source); + + ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); + Eclipse.setGeneratedBy(returnFalse, source); + + IfStatement ifNotCanEqual = new IfStatement(notOtherCanEqual, returnFalse, pS, pE); + Eclipse.setGeneratedBy(ifNotCanEqual, source); + + statements.add(ifNotCanEqual); + } + } + + /* if (!super.equals(o)) return false; */ + if (callSuper) { + MessageSend callToSuper = new MessageSend(); + callToSuper.sourceStart = pS; callToSuper.sourceEnd = pE; + Eclipse.setGeneratedBy(callToSuper, source); + callToSuper.receiver = new SuperReference(pS, pE); + Eclipse.setGeneratedBy(callToSuper.receiver, source); + callToSuper.selector = "equals".toCharArray(); + SingleNameReference oRef = new SingleNameReference(new char[] { 'o' }, p); + Eclipse.setGeneratedBy(oRef, source); + callToSuper.arguments = new Expression[] {oRef}; + Expression superNotEqual = new UnaryExpression(callToSuper, OperatorIds.NOT); + Eclipse.setGeneratedBy(superNotEqual, source); + FalseLiteral falseLiteral = new FalseLiteral(pS, pE); + Eclipse.setGeneratedBy(falseLiteral, source); + ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); + Eclipse.setGeneratedBy(returnFalse, source); + IfStatement ifSuperEquals = new IfStatement(superNotEqual, returnFalse, pS, pE); + Eclipse.setGeneratedBy(ifSuperEquals, source); + statements.add(ifSuperEquals); + } + for (EclipseNode field : fields) { TypeReference fType = getFieldType(field, useFieldsDirectly); char[] token = fType.getLastToken(); Expression thisFieldAccessor = createFieldAccessor(field, useFieldsDirectly, source); - Expression otherFieldAccessor = createFieldAccessor(field, useFieldsDirectly, source, otherN); + Expression otherFieldAccessor = createFieldAccessor(field, useFieldsDirectly, source, otherName); if (fType.dimensions() == 0 && token != null) { if (Arrays.equals(TypeConstants.FLOAT, token)) { @@ -589,7 +621,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA Eclipse.setGeneratedBy(equalsCall, source); equalsCall.receiver = createFieldAccessor(field, useFieldsDirectly, source); equalsCall.selector = "equals".toCharArray(); - equalsCall.arguments = new Expression[] { createFieldAccessor(field, useFieldsDirectly, source, otherN) }; + equalsCall.arguments = new Expression[] { createFieldAccessor(field, useFieldsDirectly, source, otherName) }; UnaryExpression fieldsNotEqual = new UnaryExpression(equalsCall, OperatorIds.NOT); fieldsNotEqual.sourceStart = pS; fieldsNotEqual.sourceEnd = pE; Eclipse.setGeneratedBy(fieldsNotEqual, source); @@ -639,6 +671,54 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA return method; } + + private MethodDeclaration createCanEqual(EclipseNode type, ASTNode source) { + /* public boolean canEquals(final java.lang.Object other) { + * return other instanceof MyType; + * } + */ + int pS = source.sourceStart; int pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + char[] otherName = "other".toCharArray(); + + MethodDeclaration method = new MethodDeclaration( + ((CompilationUnitDeclaration) type.top().get()).compilationResult); + Eclipse.setGeneratedBy(method, source); + method.modifiers = EclipseHandlerUtil.toEclipseModifier(AccessLevel.PUBLIC); + method.returnType = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); + method.returnType.sourceStart = pS; method.returnType.sourceEnd = pE; + Eclipse.setGeneratedBy(method.returnType, source); + method.selector = "canEqual".toCharArray(); + method.thrownExceptions = null; + method.typeParameters = null; + method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart; + method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd; + TypeReference objectRef = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] { p, p, p }); + Eclipse.setGeneratedBy(objectRef, source); + method.arguments = new Argument[] {new Argument(otherName, 0, objectRef, Modifier.FINAL)}; + method.arguments[0].sourceStart = pS; method.arguments[0].sourceEnd = pE; + Eclipse.setGeneratedBy(method.arguments[0], source); + + SingleNameReference otherRef = new SingleNameReference(otherName, p); + Eclipse.setGeneratedBy(otherRef, source); + + SingleTypeReference typeReference = new SingleTypeReference(((TypeDeclaration)type.get()).name, p); + Eclipse.setGeneratedBy(typeReference, source); + + InstanceOfExpression instanceOf = new InstanceOfExpression(otherRef, typeReference); + instanceOf.sourceStart = pS; instanceOf.sourceEnd = pE; + Eclipse.setGeneratedBy(instanceOf, source); + + ReturnStatement returnStatement = new ReturnStatement(instanceOf, pS, pE); + Eclipse.setGeneratedBy(returnStatement, source); + + method.statements = new Statement[] {returnStatement}; + return method; + } + + private IfStatement generateCompareFloatOrDouble(Expression thisRef, Expression otherRef, char[] floatOrDouble, ASTNode source) { int pS = source.sourceStart, pE = source.sourceEnd; /* if (Float.compare(fieldName, other.fieldName) != 0) return false */ diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index b2d64f05..c5475fb1 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -479,5 +479,4 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd private JCStatement returnBool(TreeMaker maker, boolean bool) { return maker.Return(maker.Literal(TypeTags.BOOLEAN, bool ? 1 : 0)); } - } |