use of lombok.core.configuration.CheckerFrameworkVersion in project lombok by rzwitserloot.
the class HandleEqualsAndHashCode method createHashCode.
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;
MethodDeclaration method = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
setGeneratedBy(method, source);
method.modifiers = toEclipseModifier(AccessLevel.PUBLIC);
method.returnType = TypeReference.baseTypeReference(TypeIds.T_int, 0);
setGeneratedBy(method.returnType, source);
Annotation overrideAnnotation = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source);
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 };
}
method.selector = "hashCode".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;
method.arguments = null;
List<Statement> statements = new ArrayList<Statement>();
boolean isEmpty = true;
for (Included<EclipseNode, EqualsAndHashCode.Include> member : members) {
TypeReference fType = getFieldType(member.getNode(), fieldAccess);
if (fType.getLastToken() != null) {
isEmpty = false;
break;
}
}
/* 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) {
LocalDeclaration primeDecl = new LocalDeclaration(PRIME, pS, pE);
setGeneratedBy(primeDecl, source);
primeDecl.modifiers |= Modifier.FINAL;
primeDecl.type = TypeReference.baseTypeReference(TypeIds.T_int, 0);
primeDecl.type.sourceStart = pS;
primeDecl.type.sourceEnd = pE;
setGeneratedBy(primeDecl.type, source);
primeDecl.initialization = makeIntLiteral(String.valueOf(HandlerUtil.primeForHashcode()).toCharArray(), source);
statements.add(primeDecl);
}
}
/* int result = ... */
{
LocalDeclaration resultDecl = new LocalDeclaration(RESULT, pS, pE);
setGeneratedBy(resultDecl, source);
final Expression init;
if (callSuper) {
/* ... super.hashCode(); */
MessageSend callToSuper = new MessageSend();
setGeneratedBy(callToSuper, source);
callToSuper.sourceStart = pS;
callToSuper.sourceEnd = pE;
callToSuper.receiver = new SuperReference(pS, pE);
setGeneratedBy(callToSuper.receiver, source);
callToSuper.selector = "hashCode".toCharArray();
init = callToSuper;
} else {
/* ... 1; */
init = makeIntLiteral("1".toCharArray(), source);
}
resultDecl.initialization = init;
resultDecl.type = TypeReference.baseTypeReference(TypeIds.T_int, 0);
resultDecl.type.sourceStart = pS;
resultDecl.type.sourceEnd = pE;
if (isEmpty && !cacheHashCode)
resultDecl.modifiers |= Modifier.FINAL;
setGeneratedBy(resultDecl.type, source);
statements.add(resultDecl);
}
for (Included<EclipseNode, EqualsAndHashCode.Include> member : members) {
EclipseNode memberNode = member.getNode();
boolean isMethod = memberNode.getKind() == Kind.METHOD;
TypeReference fType = getFieldType(memberNode, fieldAccess);
char[] dollarFieldName = ((isMethod ? "$$" : "$") + memberNode.getName()).toCharArray();
char[] token = fType.getLastToken();
Expression fieldAccessor = isMethod ? createMethodAccessor(memberNode, source) : createFieldAccessor(memberNode, fieldAccess, source);
if (fType.dimensions() == 0 && token != null) {
if (Arrays.equals(TypeConstants.BOOLEAN, token)) {
/* booleanField ? X : Y */
IntLiteral intTrue = makeIntLiteral(String.valueOf(HandlerUtil.primeForTrue()).toCharArray(), source);
IntLiteral intFalse = makeIntLiteral(String.valueOf(HandlerUtil.primeForFalse()).toCharArray(), source);
ConditionalExpression intForBool = new ConditionalExpression(fieldAccessor, intTrue, intFalse);
setGeneratedBy(intForBool, source);
statements.add(createResultCalculation(source, intForBool));
} else if (Arrays.equals(TypeConstants.LONG, token)) {
/* (int)(ref >>> 32 ^ ref) */
statements.add(createLocalDeclaration(source, dollarFieldName, TypeReference.baseTypeReference(TypeIds.T_long, 0), fieldAccessor));
SingleNameReference copy1 = new SingleNameReference(dollarFieldName, p);
setGeneratedBy(copy1, source);
SingleNameReference copy2 = new SingleNameReference(dollarFieldName, p);
setGeneratedBy(copy2, source);
statements.add(createResultCalculation(source, longToIntForHashCode(copy1, copy2, source)));
} else if (Arrays.equals(TypeConstants.FLOAT, token)) {
/* Float.floatToIntBits(fieldName) */
MessageSend floatToIntBits = new MessageSend();
floatToIntBits.sourceStart = pS;
floatToIntBits.sourceEnd = pE;
setGeneratedBy(floatToIntBits, source);
floatToIntBits.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_FLOAT);
floatToIntBits.selector = FLOAT_TO_INT_BITS;
floatToIntBits.arguments = new Expression[] { fieldAccessor };
statements.add(createResultCalculation(source, floatToIntBits));
} else if (Arrays.equals(TypeConstants.DOUBLE, token)) {
/* longToIntForHashCode(Double.doubleToLongBits(fieldName)) */
MessageSend doubleToLongBits = new MessageSend();
doubleToLongBits.sourceStart = pS;
doubleToLongBits.sourceEnd = pE;
setGeneratedBy(doubleToLongBits, source);
doubleToLongBits.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_DOUBLE);
doubleToLongBits.selector = DOUBLE_TO_LONG_BITS;
doubleToLongBits.arguments = new Expression[] { fieldAccessor };
statements.add(createLocalDeclaration(source, dollarFieldName, TypeReference.baseTypeReference(TypeIds.T_long, 0), doubleToLongBits));
SingleNameReference copy1 = new SingleNameReference(dollarFieldName, p);
setGeneratedBy(copy1, source);
SingleNameReference copy2 = new SingleNameReference(dollarFieldName, p);
setGeneratedBy(copy2, source);
statements.add(createResultCalculation(source, longToIntForHashCode(copy1, copy2, source)));
} else if (BUILT_IN_TYPES.contains(new String(token))) {
statements.add(createResultCalculation(source, fieldAccessor));
} else /* objects */
{
/* final java.lang.Object $fieldName = this.fieldName; */
/* $fieldName == null ? NULL_PRIME : $fieldName.hashCode() */
statements.add(createLocalDeclaration(source, dollarFieldName, generateQualifiedTypeRef(source, TypeConstants.JAVA_LANG_OBJECT), fieldAccessor));
SingleNameReference copy1 = new SingleNameReference(dollarFieldName, p);
setGeneratedBy(copy1, source);
SingleNameReference copy2 = new SingleNameReference(dollarFieldName, p);
setGeneratedBy(copy2, source);
MessageSend hashCodeCall = new MessageSend();
hashCodeCall.sourceStart = pS;
hashCodeCall.sourceEnd = pE;
setGeneratedBy(hashCodeCall, source);
hashCodeCall.receiver = copy1;
hashCodeCall.selector = HASH_CODE;
NullLiteral nullLiteral = new NullLiteral(pS, pE);
setGeneratedBy(nullLiteral, source);
EqualExpression objIsNull = new EqualExpression(copy2, nullLiteral, OperatorIds.EQUAL_EQUAL);
setGeneratedBy(objIsNull, source);
IntLiteral intMagic = makeIntLiteral(String.valueOf(HandlerUtil.primeForNull()).toCharArray(), source);
ConditionalExpression nullOrHashCode = new ConditionalExpression(objIsNull, intMagic, hashCodeCall);
nullOrHashCode.sourceStart = pS;
nullOrHashCode.sourceEnd = pE;
setGeneratedBy(nullOrHashCode, source);
statements.add(createResultCalculation(source, nullOrHashCode));
}
} else if (fType.dimensions() > 0 && token != null) {
/* Arrays.deepHashCode(array) //just hashCode for simple arrays */
MessageSend arraysHashCodeCall = new MessageSend();
arraysHashCodeCall.sourceStart = pS;
arraysHashCodeCall.sourceEnd = pE;
setGeneratedBy(arraysHashCodeCall, source);
arraysHashCodeCall.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA, TypeConstants.UTIL, "Arrays".toCharArray());
if (fType.dimensions() > 1 || !BUILT_IN_TYPES.contains(new String(token))) {
arraysHashCodeCall.selector = "deepHashCode".toCharArray();
} else {
arraysHashCodeCall.selector = "hashCode".toCharArray();
}
arraysHashCodeCall.arguments = new Expression[] { fieldAccessor };
statements.add(createResultCalculation(source, arraysHashCodeCall));
}
}
/*
* 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);
ReturnStatement returnStatement = new ReturnStatement(resultRef, pS, pE);
setGeneratedBy(returnStatement, source);
statements.add(returnStatement);
}
method.statements = statements.toArray(new Statement[0]);
return method;
}
Aggregations