From 5a13db5dc967367b9e3ec85bb5f07e65a1df09b7 Mon Sep 17 00:00:00 2001 From: Roel Spilker Date: Sun, 29 Apr 2012 22:24:59 +0200 Subject: Issue 366: don't call the getter twice, fixed for javac. --- .../javac/handlers/HandleEqualsAndHashCode.java | 116 ++++++++++++--------- 1 file changed, 68 insertions(+), 48 deletions(-) (limited to 'src/core') diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index 00601b56..9869cf94 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 The Project Lombok Authors. + * Copyright (C) 2009-2012 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,17 +21,19 @@ */ package lombok.javac.handlers; -import static lombok.javac.handlers.JavacHandlerUtil.*; import static lombok.javac.Javac.getCtcInt; +import static lombok.javac.handlers.JavacHandlerUtil.*; import java.util.ArrayList; import java.util.Collections; import lombok.EqualsAndHashCode; -import lombok.core.AnnotationValues; import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.handlers.JavacHandlerUtil.FieldAccess; +import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; import org.mangosdk.spi.ProviderFor; @@ -39,13 +41,13 @@ 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.TreeMaker; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; import com.sun.tools.javac.tree.JCTree.JCBinary; 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.JCExpressionStatement; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCModifiers; @@ -54,6 +56,7 @@ import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCUnary; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; @@ -63,6 +66,9 @@ import com.sun.tools.javac.util.Name; */ @ProviderFor(JavacAnnotationHandler.class) public class HandleEqualsAndHashCode extends JavacAnnotationHandler { + private static final String RESULT_NAME = "result"; + private static final String PRIME_NAME = "PRIME"; + private void checkForBogusFieldNames(JavacNode type, AnnotationValues annotation) { if (annotation.isExplicit("exclude")) { for (int i : createListOfNonExistentFields(List.from(annotation.getInstance().exclude()), type, true, true)) { @@ -214,8 +220,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler statements = ListBuffer.lb(); - Name primeName = typeNode.toName("PRIME"); - Name resultName = typeNode.toName("result"); + Name primeName = typeNode.toName(PRIME_NAME); + Name resultName = typeNode.toName(RESULT_NAME); /* final int PRIME = 31; */ { if (!fields.isEmpty() || callSuper) { statements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), @@ -227,16 +233,14 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler intoResult = ListBuffer.lb(); - if (callSuper) { JCMethodInvocation callToSuper = maker.Apply(List.nil(), maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("hashCode")), List.nil()); - intoResult.append(callToSuper); + statements.append(createResultCalculation(typeNode, callToSuper)); } - int tempCounter = 0; + Name dollar = typeNode.toName("$"); for (JavacNode fieldNode : fields) { JCExpression fType = getFieldType(fieldNode, fieldAccess); JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess); @@ -244,28 +248,31 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandlernil(), chainDots(typeNode, "java", "lang", "Float", "floatToIntBits"), - List.of(fieldAccessor))); + List.of(fieldAccessor)))); break; - case DOUBLE: - /* longToIntForHashCode(Double.doubleToLongBits(this.fieldName)) */ - Name tempVar = typeNode.toName("temp" + (++tempCounter)); - JCExpression init = maker.Apply( - List.nil(), - chainDots(typeNode, "java", "lang", "Double", "doubleToLongBits"), - List.of(fieldAccessor)); - statements.append( - maker.VarDef(maker.Modifiers(Flags.FINAL), tempVar, maker.TypeIdent(TypeTags.LONG), init)); - intoResult.append(longToIntForHashCode(maker, maker.Ident(tempVar), maker.Ident(tempVar))); + case DOUBLE: { + /* longToIntForHashCode(Double.doubleToLongBits(this.fieldName)) */ + Name dollarFieldName = dollar.append(((JCVariableDecl)fieldNode.get()).name); + JCExpression init = maker.Apply( + List.nil(), + chainDots(typeNode, "java", "lang", "Double", "doubleToLongBits"), + List.of(fieldAccessor)); + statements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), dollarFieldName, maker.TypeIdent(TypeTags.LONG), init)); + statements.append(createResultCalculation(typeNode, longToIntForHashCode(maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName)))); + } break; default: case BYTE: @@ -273,7 +280,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandlernil(), hcMethod, List.of(fieldAccessor))); + statements.append(createResultCalculation(typeNode, maker.Apply(List.nil(), hcMethod, List.of(fieldAccessor)))); } else /* objects */ { - /* this.fieldName == null ? 0 : this.fieldName.hashCode() */ - JCExpression hcCall = maker.Apply(List.nil(), maker.Select(createFieldAccessor(maker, fieldNode, fieldAccess), typeNode.toName("hashCode")), + /* final java.lang.Object $fieldName = this.fieldName; */ + /* $fieldName == null ? 0 : $fieldName.hashCode() */ + + Name dollarFieldName = dollar.append(((JCVariableDecl)fieldNode.get()).name); + statements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), dollarFieldName, chainDots(typeNode, "java", "lang", "Object"), fieldAccessor)); + + JCExpression hcCall = maker.Apply(List.nil(), maker.Select(maker.Ident(dollarFieldName), typeNode.toName("hashCode")), List.nil()); - JCExpression thisEqualsNull = maker.Binary(getCtcInt(JCTree.class, "EQ"), fieldAccessor, maker.Literal(getCtcInt(TypeTags.class, "BOT"), null)); - intoResult.append( - maker.Conditional(thisEqualsNull, maker.Literal(0), hcCall)); + JCExpression thisEqualsNull = maker.Binary(getCtcInt(JCTree.class, "EQ"), maker.Ident(dollarFieldName), maker.Literal(getCtcInt(TypeTags.class, "BOT"), null)); + statements.append(createResultCalculation(typeNode, maker.Conditional(thisEqualsNull, maker.Literal(0), hcCall))); } } - /* fold each intoResult entry into: - result = result * PRIME + (item); */ - for (JCExpression expr : intoResult) { - JCExpression mult = maker.Binary(getCtcInt(JCTree.class, "MUL"), maker.Ident(resultName), maker.Ident(primeName)); - JCExpression add = maker.Binary(getCtcInt(JCTree.class, "PLUS"), mult, expr); - statements.append(maker.Exec(maker.Assign(maker.Ident(resultName), add))); - } - /* return result; */ { statements.append(maker.Return(maker.Ident(resultName))); } @@ -311,6 +313,15 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandlernil(), List.nil(), List.nil(), body, null), source); } + + private JCExpressionStatement createResultCalculation(JavacNode typeNode, JCExpression expr) { + /* result = result * PRIME + (expr); */ + TreeMaker maker = typeNode.getTreeMaker(); + Name resultName = typeNode.toName(RESULT_NAME); + JCExpression mult = maker.Binary(getCtcInt(JCTree.class, "MUL"), maker.Ident(resultName), maker.Ident(typeNode.toName(PRIME_NAME))); + JCExpression add = maker.Binary(getCtcInt(JCTree.class, "PLUS"), mult, expr); + return maker.Exec(maker.Assign(maker.Ident(resultName), add)); + } /** The 2 references must be clones of each other. */ private JCExpression longToIntForHashCode(TreeMaker maker, JCExpression ref1, JCExpression ref2) { @@ -410,6 +421,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandlernil(), eqMethod, args)), returnBool(maker, false), null)); } else /* objects */ { - /* if (this.fieldName == null ? other.fieldName != null : !this.fieldName.equals(other.fieldName)) return false; */ - JCExpression thisEqualsNull = maker.Binary(getCtcInt(JCTree.class, "EQ"), thisFieldAccessor, maker.Literal(getCtcInt(TypeTags.class, "BOT"), null)); - JCExpression otherNotEqualsNull = maker.Binary(getCtcInt(JCTree.class, "NE"), otherFieldAccessor, maker.Literal(getCtcInt(TypeTags.class, "BOT"), null)); - JCExpression equalsArg = createFieldAccessor(maker, fieldNode, fieldAccess, maker.Ident(otherName)); - JCExpression castEqualsArg = maker.TypeCast(chainDots(typeNode, "java", "lang", "Object"), equalsArg); + /* final java.lang.Object this$fieldName = this.fieldName; */ + /* final java.lang.Object other$fieldName = other.fieldName; */ + /* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false;; */ + Name fieldName = ((JCVariableDecl)fieldNode.get()).name; + Name thisDollarFieldName = thisDollar.append(fieldName); + Name otherDollarFieldName = otherDollar.append(fieldName); + + statements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), thisDollarFieldName, chainDots(typeNode, "java", "lang", "Object"), thisFieldAccessor)); + statements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), otherDollarFieldName, chainDots(typeNode, "java", "lang", "Object"), otherFieldAccessor)); + + JCExpression thisEqualsNull = maker.Binary(getCtcInt(JCTree.class, "EQ"), maker.Ident(thisDollarFieldName), maker.Literal(getCtcInt(TypeTags.class, "BOT"), null)); + JCExpression otherNotEqualsNull = maker.Binary(getCtcInt(JCTree.class, "NE"), maker.Ident(otherDollarFieldName), maker.Literal(getCtcInt(TypeTags.class, "BOT"), null)); JCExpression thisEqualsThat = maker.Apply(List.nil(), - maker.Select(createFieldAccessor(maker, fieldNode, fieldAccess), typeNode.toName("equals")), - List.of(castEqualsArg)); + maker.Select(maker.Ident(thisDollarFieldName), typeNode.toName("equals")), + List.of(maker.Ident(otherDollarFieldName))); JCExpression fieldsAreNotEqual = maker.Conditional(thisEqualsNull, otherNotEqualsNull, maker.Unary(getCtcInt(JCTree.class, "NOT"), thisEqualsThat)); statements.append(maker.If(fieldsAreNotEqual, returnBool(maker, false), null)); } -- cgit