Search in sources :

Example 6 with CheckerFrameworkVersion

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;
}
Also used : ArrayList(java.util.ArrayList) EqualExpression(org.eclipse.jdt.internal.compiler.ast.EqualExpression) SingleNameReference(org.eclipse.jdt.internal.compiler.ast.SingleNameReference) SuperReference(org.eclipse.jdt.internal.compiler.ast.SuperReference) Assignment(org.eclipse.jdt.internal.compiler.ast.Assignment) IfStatement(org.eclipse.jdt.internal.compiler.ast.IfStatement) MessageSend(org.eclipse.jdt.internal.compiler.ast.MessageSend) ReturnStatement(org.eclipse.jdt.internal.compiler.ast.ReturnStatement) IntLiteral(org.eclipse.jdt.internal.compiler.ast.IntLiteral) TypeReference(org.eclipse.jdt.internal.compiler.ast.TypeReference) ParameterizedSingleTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) LocalDeclaration(org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) FieldReference(org.eclipse.jdt.internal.compiler.ast.FieldReference) MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) Statement(org.eclipse.jdt.internal.compiler.ast.Statement) ReturnStatement(org.eclipse.jdt.internal.compiler.ast.ReturnStatement) IfStatement(org.eclipse.jdt.internal.compiler.ast.IfStatement) ConditionalExpression(org.eclipse.jdt.internal.compiler.ast.ConditionalExpression) ThisReference(org.eclipse.jdt.internal.compiler.ast.ThisReference) MarkerAnnotation(org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation) Annotation(org.eclipse.jdt.internal.compiler.ast.Annotation) Expression(org.eclipse.jdt.internal.compiler.ast.Expression) BinaryExpression(org.eclipse.jdt.internal.compiler.ast.BinaryExpression) ConditionalExpression(org.eclipse.jdt.internal.compiler.ast.ConditionalExpression) InstanceOfExpression(org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression) UnaryExpression(org.eclipse.jdt.internal.compiler.ast.UnaryExpression) EqualExpression(org.eclipse.jdt.internal.compiler.ast.EqualExpression) CastExpression(org.eclipse.jdt.internal.compiler.ast.CastExpression) EclipseNode(lombok.eclipse.EclipseNode) CheckerFrameworkVersion(lombok.core.configuration.CheckerFrameworkVersion) NullLiteral(org.eclipse.jdt.internal.compiler.ast.NullLiteral)

Aggregations

CheckerFrameworkVersion (lombok.core.configuration.CheckerFrameworkVersion)6 JCAnnotation (com.sun.tools.javac.tree.JCTree.JCAnnotation)5 JCBlock (com.sun.tools.javac.tree.JCTree.JCBlock)5 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)5 JCTypeParameter (com.sun.tools.javac.tree.JCTree.JCTypeParameter)5 JCVariableDecl (com.sun.tools.javac.tree.JCTree.JCVariableDecl)5 Name (com.sun.tools.javac.util.Name)5 JCStatement (com.sun.tools.javac.tree.JCTree.JCStatement)4 ListBuffer (com.sun.tools.javac.util.ListBuffer)4 JavacNode (lombok.javac.JavacNode)4 JCModifiers (com.sun.tools.javac.tree.JCTree.JCModifiers)3 JCPrimitiveTypeTree (com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree)3 JavacTreeMaker (lombok.javac.JavacTreeMaker)3 JCArrayTypeTree (com.sun.tools.javac.tree.JCTree.JCArrayTypeTree)2 JCMethodDecl (com.sun.tools.javac.tree.JCTree.JCMethodDecl)2 JCNewClass (com.sun.tools.javac.tree.JCTree.JCNewClass)2 JCReturn (com.sun.tools.javac.tree.JCTree.JCReturn)2 ArrayList (java.util.ArrayList)2 Accessors (lombok.experimental.Accessors)2 JCConditional (com.sun.tools.javac.tree.JCTree.JCConditional)1