All Downloads are FREE. Search and download functionalities are using the official Maven repository.

framework.src.org.checkerframework.common.value.ValueTransfer Maven / Gradle / Ivy

package org.checkerframework.common.value;

import org.checkerframework.common.value.qual.BoolVal;
import org.checkerframework.common.value.qual.BottomVal;
import org.checkerframework.common.value.qual.DoubleVal;
import org.checkerframework.common.value.qual.IntVal;
import org.checkerframework.common.value.qual.StringVal;
import org.checkerframework.common.value.qual.UnknownVal;
import org.checkerframework.common.value.util.NumberMath;
import org.checkerframework.common.value.util.NumberUtils;
import org.checkerframework.dataflow.analysis.RegularTransferResult;
import org.checkerframework.dataflow.analysis.TransferInput;
import org.checkerframework.dataflow.analysis.TransferResult;
import org.checkerframework.dataflow.cfg.node.*;
import org.checkerframework.framework.flow.CFAbstractAnalysis;
import org.checkerframework.framework.flow.CFStore;
import org.checkerframework.framework.flow.CFTransfer;
import org.checkerframework.framework.flow.CFValue;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.TypesUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;

public class ValueTransfer extends CFTransfer {
    AnnotatedTypeFactory atypefactory;

    public ValueTransfer(
            CFAbstractAnalysis analysis) {
        super(analysis);
        atypefactory = analysis.getTypeFactory();
    }

    private List getStringValues(Node subNode,
            TransferInput p) {
        CFValue value = p.getValueOfSubNode(subNode);
        // @StringVal, @BottomVal, @UnknownVal
        AnnotationMirror numberAnno = value.getType().getAnnotation(
                StringVal.class);
        if (numberAnno != null) {
            return AnnotationUtils.getElementValueArray(numberAnno, "value",
                    String.class, true);
        }
        numberAnno = value.getType().getAnnotation(UnknownVal.class);
        if (numberAnno != null) {
            return new ArrayList();
        }
        numberAnno = value.getType().getAnnotation(BottomVal.class);
        if (numberAnno != null) {
            return Collections.singletonList("null");
        }

        //@IntVal, @DoubleVal, @BoolVal (have to be converted to string)
        List values;
        numberAnno = value.getType().getAnnotation(BoolVal.class);
        if (numberAnno != null) {
            values = getBooleanValues(subNode, p);
        } else if (subNode.getType().getKind() == TypeKind.CHAR) {
            values = getCharValues(subNode, p);
        } else if (subNode instanceof StringConversionNode) {
           return getStringValues(
                    ((StringConversionNode) subNode).getOperand(), p);
        } else {
            values = getNumericalValues(subNode, p);
        }
        List stringValues = new ArrayList();
        for (Object o : values) {
            stringValues.add(o.toString());
        }
        return stringValues;
    }

    private List getBooleanValues(Node subNode,
            TransferInput p) {
        CFValue value = p.getValueOfSubNode(subNode);
        AnnotationMirror intAnno = value.getType().getAnnotation(BoolVal.class);
        return ValueAnnotatedTypeFactory.getBooleanValues(intAnno);
    }

    private List getCharValues(Node subNode,
            TransferInput p) {
        CFValue value = p.getValueOfSubNode(subNode);
        AnnotationMirror intAnno = value.getType().getAnnotation(IntVal.class);
        return ValueAnnotatedTypeFactory.getCharValues(intAnno);
    }

    private List getNumericalValues(Node subNode,
            TransferInput p) {
        CFValue value = p.getValueOfSubNode(subNode);
        AnnotationMirror numberAnno = value.getType().getAnnotation(
                IntVal.class);
        List values;
        if (numberAnno == null) {
            numberAnno = value.getType().getAnnotation(DoubleVal.class);
            if (numberAnno != null) {
                values = AnnotationUtils.getElementValueArray(numberAnno,
                        "value", Double.class, true);
            } else {
                return new ArrayList();

            }
        } else {
            values = AnnotationUtils.getElementValueArray(numberAnno, "value",
                    Long.class, true);
        }
        return NumberUtils.castNumbers(subNode.getType(), values);
    }

    private AnnotationMirror createStringValAnnotationMirror(List values) {
        if (values.isEmpty()) {
            return ((ValueAnnotatedTypeFactory) atypefactory).UNKNOWNVAL;
        }
        return ((ValueAnnotatedTypeFactory) atypefactory)
                .createStringAnnotation(values);
    }

    private AnnotationMirror createNumberAnnotationMirror(List values) {
        if (values.isEmpty()) {
            return ((ValueAnnotatedTypeFactory) atypefactory).UNKNOWNVAL;
        }
        Number first = values.get(0);
        if (first instanceof Integer || first instanceof Short
                || first instanceof Long) {
            List intValues = new ArrayList<>();
            for (Number number : values) {
                intValues.add(number.longValue());
            }
            return ((ValueAnnotatedTypeFactory) atypefactory)
                    .createIntValAnnotation(intValues);
        }
        if (first instanceof Double || first instanceof Float) {
            List intValues = new ArrayList<>();
            for (Number number : values) {
                intValues.add(number.doubleValue());
            }
            return ((ValueAnnotatedTypeFactory) atypefactory)
                    .createDoubleValAnnotation(intValues);
        }
        throw new UnsupportedOperationException();
    }

    private AnnotationMirror createBooleanAnnotationMirror(List values) {
        if (values.isEmpty()) {
            return ((ValueAnnotatedTypeFactory) atypefactory).UNKNOWNVAL;
        }
        return ((ValueAnnotatedTypeFactory) atypefactory)
                .createBooleanAnnotation(values);

    }

    private TransferResult createNewResult(
            TransferResult result, List resultValues) {
        AnnotationMirror stringVal = createNumberAnnotationMirror(resultValues);
        CFValue newResultValue = analysis.createSingleAnnotationValue(
                stringVal, result.getResultValue().getType()
                        .getUnderlyingType());
        return new RegularTransferResult<>(newResultValue,
                result.getRegularStore());
    }

    private TransferResult createNewResultBoolean(
            TransferResult result, List resultValues) {
        AnnotationMirror stringVal = createBooleanAnnotationMirror(resultValues);
        CFValue newResultValue = analysis.createSingleAnnotationValue(
                stringVal, result.getResultValue().getType()
                                 .getUnderlyingType());
        return new RegularTransferResult<>(newResultValue,
                result.getRegularStore());
    }

    @Override
    public TransferResult visitStringConcatenateAssignment(StringConcatenateAssignmentNode n,
                                                                             TransferInput p) {
        TransferResult result = super.visitStringConcatenateAssignment(n, p);
        return stringConcatenation(n.getLeftOperand(), n.getRightOperand(), p, result);
    }

    @Override
    public TransferResult visitStringConcatenate(StringConcatenateNode n,
                                                                   TransferInput p) {
        TransferResult result = super.visitStringConcatenate(n, p);
        return stringConcatenation(n.getLeftOperand(), n.getRightOperand(), p, result);
    }

    public TransferResult stringConcatenation(Node leftOperand, Node rightOperand,
                                                                TransferInput p,
                                                                TransferResult result) {
        List lefts = getStringValues(leftOperand, p);
        List rights = getStringValues(rightOperand, p);
        List concat = new ArrayList<>();
        for (String left : lefts) {
            for (String right : rights) {
                concat.add(left + right);
            }
        }
        AnnotationMirror stringVal = createStringValAnnotationMirror(concat);
        TypeMirror underlyingType = result.getResultValue().getType().getUnderlyingType();
        CFValue newResultValue = analysis.createSingleAnnotationValue(stringVal, underlyingType);
        return new RegularTransferResult<>(newResultValue, result.getRegularStore());
    }

    enum NumbericalBinaryOps {
        ADDTION, SUBTRACTION, DIVISION, REMAINDER, MULPLICATION, SHIFT_LEFT, SIGNED_SHIFT_RIGHT, UNSIGNED_SHIFT_RIGHT, BITWISE_AND, BITWISE_OR, BITWISE_XOR;
    }

    private List calcutateNumericalBinaryOp(Node leftNode,
            Node rightNode, NumbericalBinaryOps op,
            TransferInput p) {
        List lefts = getNumericalValues(leftNode, p);
        List rights = getNumericalValues(rightNode, p);
        List resultValues = new ArrayList<>();
        for (Number left : lefts) {
            NumberMath nmLeft = NumberMath.getNumberMath(left);
            for (Number right : rights) {
                switch (op) {
                case ADDTION:
                    resultValues.add(nmLeft.plus(right));
                    break;
                case DIVISION:
                    resultValues.add(nmLeft.divide(right));
                    break;
                case MULPLICATION:
                    resultValues.add(nmLeft.times(right));
                    break;
                case REMAINDER:
                    resultValues.add(nmLeft.remainder(right));
                    break;
                case SUBTRACTION:
                    resultValues.add(nmLeft.minus(right));
                    break;
                case SHIFT_LEFT:
                    resultValues.add(nmLeft.shiftLeft(right));
                    break;
                case SIGNED_SHIFT_RIGHT:
                    resultValues.add(nmLeft.signedSiftRight(right));
                    break;
                case UNSIGNED_SHIFT_RIGHT:
                    resultValues.add(nmLeft.unsignedSiftRight(right));
                    break;
                case BITWISE_AND:
                    resultValues.add(nmLeft.bitwiseAnd(right));
                    break;
                case BITWISE_OR:
                    resultValues.add(nmLeft.bitwiseOr(right));
                    break;
                case BITWISE_XOR:
                    resultValues.add(nmLeft.bitwiseXor(right));
                    break;
                default:
                    throw new UnsupportedOperationException();
                }
            }
        }
        return resultValues;
    }

    @Override
    public TransferResult visitNumericalAddition(
            NumericalAdditionNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitNumericalAddition(n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.ADDTION, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitNumericalSubtraction(
            NumericalSubtractionNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitNumericalSubtraction(n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.SUBTRACTION, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitNumericalMultiplication(
            NumericalMultiplicationNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitNumericalMultiplication(n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.MULPLICATION, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitIntegerDivision(
            IntegerDivisionNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitIntegerDivision(n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.DIVISION, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitFloatingDivision(
            FloatingDivisionNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitFloatingDivision(n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.DIVISION, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitIntegerRemainder(
            IntegerRemainderNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitIntegerRemainder(n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.REMAINDER, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitFloatingRemainder(
            FloatingRemainderNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitFloatingRemainder(n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.REMAINDER, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitLeftShift(LeftShiftNode n,
            TransferInput p) {
        TransferResult transferResult = super.visitLeftShift(
                n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.SHIFT_LEFT, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitSignedRightShift(
            SignedRightShiftNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitSignedRightShift(n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.SIGNED_SHIFT_RIGHT, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitUnsignedRightShift(
            UnsignedRightShiftNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitUnsignedRightShift(n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.UNSIGNED_SHIFT_RIGHT, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitBitwiseAnd(BitwiseAndNode n,
            TransferInput p) {
        TransferResult transferResult = super
                .visitBitwiseAnd(n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.BITWISE_AND, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitBitwiseOr(BitwiseOrNode n,
            TransferInput p) {
        TransferResult transferResult = super.visitBitwiseOr(
                n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.BITWISE_OR, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitBitwiseXor(BitwiseXorNode n,
            TransferInput p) {
        TransferResult transferResult = super
                .visitBitwiseXor(n, p);
        List resultValues = calcutateNumericalBinaryOp(
                n.getLeftOperand(), n.getRightOperand(),
                NumbericalBinaryOps.BITWISE_XOR, p);
        return createNewResult(transferResult, resultValues);
    }

    enum NumbericalUnaryOps {
        PLUS, MINUS, BITWISE_COMPLEMENT;
    }

    private List calcutateNumericalUnaryOp(Node operand,
            NumbericalUnaryOps op, TransferInput p) {
        List lefts = getNumericalValues(operand, p);
        List resultValues = new ArrayList<>();
        for (Number left : lefts) {
            NumberMath nmLeft = NumberMath.getNumberMath(left);
            switch (op) {
            case PLUS:
                resultValues.add(nmLeft.unaryPlus());
                break;
            case MINUS:
                resultValues.add(nmLeft.unaryMinus());
                break;
            case BITWISE_COMPLEMENT:
                resultValues.add(nmLeft.bitwiseComplement());
                break;
            default:
                throw new UnsupportedOperationException();
            }

        }
        return resultValues;
    }

    @Override
    public TransferResult visitNumericalMinus(
            NumericalMinusNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitNumericalMinus(n, p);
        List resultValues = calcutateNumericalUnaryOp(n.getOperand(),
                NumbericalUnaryOps.MINUS, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitNumericalPlus(
            NumericalPlusNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitNumericalPlus(n, p);
        List resultValues = calcutateNumericalUnaryOp(n.getOperand(),
                NumbericalUnaryOps.PLUS, p);
        return createNewResult(transferResult, resultValues);
    }

    @Override
    public TransferResult visitBitwiseComplement(
            BitwiseComplementNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitBitwiseComplement(n, p);
        List resultValues = calcutateNumericalUnaryOp(n.getOperand(),
                NumbericalUnaryOps.BITWISE_COMPLEMENT, p);
        return createNewResult(transferResult, resultValues);
    }

    enum ComparisonOperators {
        EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_EQ, LESS_THAN, LESS_THAN_EQ;
    }

    private List calcutateBinaryComparison(Node leftNode,
            Node rightNode, ComparisonOperators op,
            TransferInput p) {
        List lefts = getNumericalValues(leftNode, p);
        List rights = getNumericalValues(rightNode, p);
        List resultValues = new ArrayList<>();
        for (Number left : lefts) {
            NumberMath nmLeft = NumberMath.getNumberMath(left);
            for (Number right : rights) {
                switch (op) {
                case EQUAL:
                    resultValues.add(nmLeft.equalTo(right));
                    break;
                case GREATER_THAN:
                    resultValues.add(nmLeft.greaterThan(right));
                    break;
                case GREATER_THAN_EQ:
                    resultValues.add(nmLeft.greaterThanEq(right));
                    break;
                case LESS_THAN:
                    resultValues.add(nmLeft.lessThan(right));
                    break;
                case LESS_THAN_EQ:
                    resultValues.add(nmLeft.lessThanEq(right));
                    break;
                case NOT_EQUAL:
                    resultValues.add(nmLeft.notEqualTo(right));
                    break;
                default:
                    throw new UnsupportedOperationException();
                }
            }
        }
        return resultValues;
    }

    @Override
    public TransferResult visitLessThan(LessThanNode n,
            TransferInput p) {
        TransferResult transferResult = super.visitLessThan(
                n, p);
        List resultValues = calcutateBinaryComparison(
                n.getLeftOperand(), n.getRightOperand(),
                ComparisonOperators.LESS_THAN, p);
        return createNewResultBoolean(transferResult, resultValues);
    }

    @Override
    public TransferResult visitLessThanOrEqual(
            LessThanOrEqualNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitLessThanOrEqual(n, p);
        List resultValues = calcutateBinaryComparison(
                n.getLeftOperand(), n.getRightOperand(),
                ComparisonOperators.LESS_THAN_EQ, p);
        return createNewResultBoolean(transferResult, resultValues);
    }

    @Override
    public TransferResult visitGreaterThan(GreaterThanNode n,
            TransferInput p) {
        TransferResult transferResult = super
                .visitGreaterThan(n, p);
        List resultValues = calcutateBinaryComparison(
                n.getLeftOperand(), n.getRightOperand(),
                ComparisonOperators.GREATER_THAN, p);
        return createNewResultBoolean(transferResult, resultValues);
    }

    @Override
    public TransferResult visitGreaterThanOrEqual(
            GreaterThanOrEqualNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitGreaterThanOrEqual(n, p);
        List resultValues = calcutateBinaryComparison(
                n.getLeftOperand(), n.getRightOperand(),
                ComparisonOperators.GREATER_THAN_EQ, p);
        return createNewResultBoolean(transferResult, resultValues);
    }

    @Override
    public TransferResult visitEqualTo(EqualToNode n,
            TransferInput p) {
        TransferResult transferResult = super.visitEqualTo(n,
                p);
        if (TypesUtils.isPrimitive(n.getLeftOperand().getType())
                || TypesUtils.isPrimitive(n.getRightOperand().getType())) {
            // At least one must be a primitive otherwise reference equality is used.
            List resultValues = calcutateBinaryComparison(
                    n.getLeftOperand(), n.getRightOperand(),
                    ComparisonOperators.EQUAL, p);
            return createNewResultBoolean(transferResult, resultValues);
        }
        return super.visitEqualTo(n, p);
    }

    @Override
    public TransferResult visitNotEqual(NotEqualNode n,
            TransferInput p) {
        TransferResult transferResult = super.visitNotEqual(
                n, p);
        if (TypesUtils.isPrimitive(n.getLeftOperand().getType())
                || TypesUtils.isPrimitive(n.getRightOperand().getType())) {
            // At least one must be a primitive otherwise reference equality is
            // used.
            List resultValues = calcutateBinaryComparison(
                    n.getLeftOperand(), n.getRightOperand(),
                    ComparisonOperators.NOT_EQUAL, p);
            return createNewResultBoolean(transferResult, resultValues);
        }
        return super.visitNotEqual(n, p);
    }

    enum ConditionalOperators {
        NOT, OR, AND;
    }

    private List calcutateCondtionalOperator(Node leftNode,
            Node rightNode, ConditionalOperators op,
            TransferInput p) {
        List lefts = getBooleanValues(leftNode, p);
        List resultValues = new ArrayList<>();
        List rights = new ArrayList();
        if (rightNode != null) {
            rights = getBooleanValues(rightNode, p);
        }
        switch (op) {
        case NOT:
            for (Boolean left : lefts) {
                resultValues.add(!left);
            }
            return resultValues;
        case OR:
            if (lefts.isEmpty() && rights.size() == 1) {
                if (rights.get(0)) {
                    // unknown || true == true
                    return rights;
                }
            }

            if (rights.isEmpty() && lefts.size() == 1) {
                if (lefts.get(0)) {
                    // true || unknown == true
                    return lefts;
                }
            }

            for (Boolean left : lefts) {
                for (Boolean right : rights) {
                    resultValues.add(left || right);
                }
            }
            return resultValues;
        case AND:
            if (lefts.isEmpty() && rights.size() == 1) {
                if (!rights.get(0)) {
                    // unknown && false == false
                    return rights;
                }
            }

            if (rights.isEmpty() && lefts.size() == 1) {
                if (!lefts.get(0)) {
                    // false && unknown == false
                    return lefts;
                }
            }

            for (Boolean left : lefts) {
                for (Boolean right : rights) {
                    resultValues.add(left && right);
                }
            }
            return resultValues;

        }

        return resultValues;
    }

    @Override
    public TransferResult visitConditionalNot(
            ConditionalNotNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitConditionalNot(n, p);
        List resultValues = calcutateCondtionalOperator(
                n.getOperand(), null, ConditionalOperators.NOT, p);
        return createNewResultBoolean(transferResult, resultValues);
    }

    @Override
    public TransferResult visitConditionalAnd(
            ConditionalAndNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitConditionalAnd(n, p);
        List resultValues = calcutateCondtionalOperator(
                n.getLeftOperand(), n.getRightOperand(),
                ConditionalOperators.AND, p);
        return createNewResultBoolean(transferResult, resultValues);
    }

    @Override
    public TransferResult visitConditionalOr(
            ConditionalOrNode n, TransferInput p) {
        TransferResult transferResult = super
                .visitConditionalOr(n, p);
        List resultValues = calcutateCondtionalOperator(
                n.getLeftOperand(), n.getRightOperand(),
                ConditionalOperators.OR, p);
        return createNewResultBoolean(transferResult, resultValues);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy