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

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

Go to download

The Checker Framework enhances Java’s type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.42.0
Show newest version
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