aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok/eclipse
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lombok/eclipse')
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java105
1 files changed, 98 insertions, 7 deletions
diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
index 7147343e..deb19c00 100755
--- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
@@ -36,6 +36,7 @@ import java.util.Set;
import lombok.AccessLevel;
import lombok.ConfigurationKeys;
import lombok.EqualsAndHashCode;
+import lombok.EqualsAndHashCode.CacheStrategy;
import lombok.core.AST.Kind;
import lombok.core.handlers.HandlerUtil;
import lombok.core.handlers.InclusionExclusionUtils;
@@ -59,6 +60,8 @@ import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
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.InstanceOfExpression;
import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
@@ -94,6 +97,9 @@ import org.mangosdk.spi.ProviderFor;
@ProviderFor(EclipseAnnotationHandler.class)
public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndHashCode> {
+ private static final String HASH_CODE_CACHE_NAME = "$hashCodeCache";
+
+ private final char[] HASH_CODE_CACHE_NAME_ARR = HASH_CODE_CACHE_NAME.toCharArray();
private final char[] PRIME = "PRIME".toCharArray();
private final char[] RESULT = "result".toCharArray();
@@ -116,7 +122,9 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
- generateMethods(annotationNode.up(), annotationNode, members, callSuper, true, fieldAccess, onParam);
+ boolean cacheHashCode = ann.cacheStrategy() == CacheStrategy.LAZY;
+
+ generateMethods(annotationNode.up(), annotationNode, members, callSuper, true, cacheHashCode, fieldAccess, onParam);
}
public void generateEqualsAndHashCodeForType(EclipseNode typeNode, EclipseNode errorNode) {
@@ -130,11 +138,11 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS);
FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD;
- generateMethods(typeNode, errorNode, members, null, false, access, new ArrayList<Annotation>());
+ generateMethods(typeNode, errorNode, members, null, false, false, access, new ArrayList<Annotation>());
}
public void generateMethods(EclipseNode typeNode, EclipseNode errorNode, List<Included<EclipseNode, EqualsAndHashCode.Include>> members,
- Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<Annotation> onParam) {
+ Boolean callSuper, boolean whineIfExists, boolean cacheHashCode, FieldAccess fieldAccess, List<Annotation> onParam) {
TypeDeclaration typeDecl = null;
@@ -222,12 +230,33 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
injectMethod(typeNode, canEqualMethod);
}
- MethodDeclaration hashCodeMethod = createHashCode(typeNode, members, callSuper, errorNode.get(), fieldAccess);
+ if (cacheHashCode){
+ if (fieldExists(HASH_CODE_CACHE_NAME, typeNode) != MemberExistsResult.NOT_EXISTS) {
+ String msg = String.format("Not caching the result of hashCode: A field named %s already exists.", HASH_CODE_CACHE_NAME);
+ errorNode.addWarning(msg);
+ cacheHashCode = false;
+ } else {
+ createHashCodeCacheField(typeNode, errorNode.get());
+ }
+ }
+
+ MethodDeclaration hashCodeMethod = createHashCode(typeNode, members, callSuper, cacheHashCode, errorNode.get(), fieldAccess);
hashCodeMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration)typeNode.get()).scope);
injectMethod(typeNode, hashCodeMethod);
}
+
+ private void createHashCodeCacheField(EclipseNode typeNode, ASTNode source) {
+ FieldDeclaration hashCodeCacheDecl = new FieldDeclaration(HASH_CODE_CACHE_NAME_ARR, 0, 0);
+ hashCodeCacheDecl.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccTransient;
+ hashCodeCacheDecl.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
+ hashCodeCacheDecl.type = TypeReference.baseTypeReference(TypeIds.T_int, 0);
+ hashCodeCacheDecl.declarationSourceEnd = -1;
+ injectFieldAndMarkGenerated(typeNode, hashCodeCacheDecl);
+ setGeneratedBy(hashCodeCacheDecl, source);
+ setGeneratedBy(hashCodeCacheDecl.type, source);
+ }
- public MethodDeclaration createHashCode(EclipseNode type, Collection<Included<EclipseNode, EqualsAndHashCode.Include>> members, boolean callSuper, ASTNode source, FieldAccess fieldAccess) {
+ public MethodDeclaration createHashCode(EclipseNode type, Collection<Included<EclipseNode, EqualsAndHashCode.Include>> members, boolean callSuper, boolean cacheHashCode, ASTNode source, FieldAccess fieldAccess) {
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long) pS << 32 | pE;
@@ -238,7 +267,10 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
method.returnType = TypeReference.baseTypeReference(TypeIds.T_int, 0);
setGeneratedBy(method.returnType, source);
Annotation overrideAnnotation = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source);
- if (getCheckerFrameworkVersion(type).generateSideEffectFree()) {
+ CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(type);
+ if (cacheHashCode && checkerFramework.generatePure()) {
+ method.annotations = new Annotation[] { overrideAnnotation, generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__PURE) };
+ } else if (checkerFramework.generateSideEffectFree()) {
method.annotations = new Annotation[] { overrideAnnotation, generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE) };
} else {
method.annotations = new Annotation[] { overrideAnnotation };
@@ -262,6 +294,22 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
}
}
+ /* if (this.$hashCodeCache != 0) return this.$hashCodeCache; */ {
+ if (cacheHashCode) {
+ FieldReference hashCodeCacheRef = new FieldReference(HASH_CODE_CACHE_NAME_ARR, p);
+ hashCodeCacheRef.receiver = new ThisReference(pS, pE);
+ setGeneratedBy(hashCodeCacheRef, source);
+ setGeneratedBy(hashCodeCacheRef.receiver, source);
+ EqualExpression cacheNotZero = new EqualExpression(hashCodeCacheRef, makeIntLiteral("0".toCharArray(), source), OperatorIds.NOT_EQUAL);
+ setGeneratedBy(cacheNotZero, source);
+ ReturnStatement returnCache = new ReturnStatement(hashCodeCacheRef, pS, pE);
+ setGeneratedBy(returnCache, source);
+ IfStatement ifStatement = new IfStatement(cacheNotZero, returnCache, pS, pE);
+ setGeneratedBy(ifStatement, source);
+ statements.add(ifStatement);
+ }
+ }
+
/* final int PRIME = X; */ {
/* Without members, PRIME isn't used, as that would trigger a 'local variable not used' warning. */
if (!isEmpty) {
@@ -296,7 +344,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
resultDecl.initialization = init;
resultDecl.type = TypeReference.baseTypeReference(TypeIds.T_int, 0);
resultDecl.type.sourceStart = pS; resultDecl.type.sourceEnd = pE;
- if (isEmpty) resultDecl.modifiers |= Modifier.FINAL;
+ if (isEmpty && !cacheHashCode) resultDecl.modifiers |= Modifier.FINAL;
setGeneratedBy(resultDecl.type, source);
statements.add(resultDecl);
}
@@ -391,6 +439,49 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
}
}
+ /*
+ * if (result == 0) result = Integer.MIN_VALUE;
+ * this.$hashCodeCache = result;
+ *
+ */ {
+ if (cacheHashCode) {
+ SingleNameReference resultRef = new SingleNameReference(RESULT, p);
+ setGeneratedBy(resultRef, source);
+
+ EqualExpression resultIsZero = new EqualExpression(resultRef, makeIntLiteral("0".toCharArray(), source), OperatorIds.EQUAL_EQUAL);
+ setGeneratedBy(resultIsZero, source);
+
+ resultRef = new SingleNameReference(RESULT, p);
+ setGeneratedBy(resultRef, source);
+
+ FieldReference integerMinValue = new FieldReference("MIN_VALUE".toCharArray(), p);
+ integerMinValue.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_INTEGER);
+ setGeneratedBy(integerMinValue, source);
+
+ Assignment newResult = new Assignment(resultRef, integerMinValue, pE);
+ newResult.sourceStart = pS; newResult.statementEnd = newResult.sourceEnd = pE;
+ setGeneratedBy(newResult, source);
+
+ IfStatement ifStatement = new IfStatement(resultIsZero, newResult, pS, pE);
+ setGeneratedBy(ifStatement, source);
+ statements.add(ifStatement);
+
+
+ FieldReference hashCodeCacheRef = new FieldReference(HASH_CODE_CACHE_NAME_ARR, p);
+ hashCodeCacheRef.receiver = new ThisReference(pS, pE);
+ setGeneratedBy(hashCodeCacheRef, source);
+ setGeneratedBy(hashCodeCacheRef.receiver, source);
+
+ resultRef = new SingleNameReference(RESULT, p);
+ setGeneratedBy(resultRef, source);
+
+ Assignment cacheResult = new Assignment(hashCodeCacheRef, resultRef, pE);
+ cacheResult.sourceStart = pS; cacheResult.statementEnd = cacheResult.sourceEnd = pE;
+ setGeneratedBy(cacheResult, source);
+ statements.add(cacheResult);
+ }
+ }
+
/* return result; */ {
SingleNameReference resultRef = new SingleNameReference(RESULT, p);
setGeneratedBy(resultRef, source);