Search in sources :

Example 16 with NewArrayTree

use of com.sun.source.tree.NewArrayTree in project checker-framework by typetools.

the class UpperBoundVisitor method relaxedCommonAssignment.

/**
 * Returns whether the assignment is legal based on the relaxed assignment rules.
 *
 * <p>The relaxed assignment rules are the following: Assuming the varType (left-hand side) is
 * less than the length of some array given some offset
 *
 * <p>1. If both the offset and the value expression (rhs) are ints known at compile time, and if
 * the min length of the array is greater than offset + value, then the assignment is legal. (This
 * method returns true.)
 *
 * <p>2. If the value expression (rhs) is less than the length of an array that is the same length
 * as the array in the varType, and if the offsets are equal, then the assignment is legal. (This
 * method returns true.)
 *
 * <p>3. Otherwise the assignment is only legal if the usual assignment rules are true, so this
 * method returns false.
 *
 * <p>If the varType is less than the length of multiple arrays, then this method only returns
 * true if the relaxed rules above apply for each array.
 *
 * <p>If the varType is an array type and the value expression is an array initializer, then the
 * above rules are applied for expression in the initializer where the varType is the component
 * type of the array.
 *
 * @param varType the type of the left-hand side (the variable in the assignment)
 * @param valueExp the right-hand side (the expression in the assignment)
 * @return true if the assignment is legal based on special Upper Bound rules
 */
private boolean relaxedCommonAssignment(AnnotatedTypeMirror varType, ExpressionTree valueExp) {
    if (valueExp.getKind() == Tree.Kind.NEW_ARRAY && varType.getKind() == TypeKind.ARRAY) {
        List<? extends ExpressionTree> expressions = ((NewArrayTree) valueExp).getInitializers();
        if (expressions == null || expressions.isEmpty()) {
            return false;
        }
        // The qualifier we need for an array is in the component type, not varType.
        AnnotatedTypeMirror componentType = ((AnnotatedArrayType) varType).getComponentType();
        UBQualifier qualifier = UBQualifier.createUBQualifier(componentType, atypeFactory.UNKNOWN, (UpperBoundChecker) checker);
        if (!qualifier.isLessThanLengthQualifier()) {
            return false;
        }
        for (ExpressionTree expressionTree : expressions) {
            if (!relaxedCommonAssignmentCheck((LessThanLengthOf) qualifier, expressionTree)) {
                return false;
            }
        }
        return true;
    }
    UBQualifier qualifier = UBQualifier.createUBQualifier(varType, atypeFactory.UNKNOWN, (UpperBoundChecker) checker);
    return qualifier.isLessThanLengthQualifier() && relaxedCommonAssignmentCheck((LessThanLengthOf) qualifier, valueExp);
}
Also used : AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType) NewArrayTree(com.sun.source.tree.NewArrayTree) LessThanLengthOf(org.checkerframework.checker.index.upperbound.UBQualifier.LessThanLengthOf) ExpressionTree(com.sun.source.tree.ExpressionTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 17 with NewArrayTree

use of com.sun.source.tree.NewArrayTree in project checker-framework by typetools.

the class PropagationTreeAnnotator method visitNewArray.

@Override
public Void visitNewArray(NewArrayTree tree, AnnotatedTypeMirror type) {
    assert type.getKind() == TypeKind.ARRAY : "PropagationTreeAnnotator.visitNewArray: should be an array type";
    AnnotatedTypeMirror componentType = ((AnnotatedArrayType) type).getComponentType();
    // prev is the lub of the initializers if they exist, otherwise the current component type.
    Set<? extends AnnotationMirror> prev = null;
    if (tree.getInitializers() != null && !tree.getInitializers().isEmpty()) {
        // the array.
        for (ExpressionTree init : tree.getInitializers()) {
            AnnotatedTypeMirror initType = atypeFactory.getAnnotatedType(init);
            // initType might be a typeVariable, so use effectiveAnnotations.
            Set<AnnotationMirror> annos = initType.getEffectiveAnnotations();
            prev = (prev == null) ? annos : qualHierarchy.leastUpperBounds(prev, annos);
        }
    } else {
        prev = componentType.getAnnotations();
    }
    assert prev != null : "PropagationTreeAnnotator.visitNewArray: violated assumption about qualifiers";
    TreePath path = atypeFactory.getPath(tree);
    AnnotatedTypeMirror contextType = null;
    if (path != null && path.getParentPath() != null) {
        Tree parentTree = path.getParentPath().getLeaf();
        if (parentTree.getKind() == Kind.ASSIGNMENT) {
            Tree var = ((AssignmentTree) parentTree).getVariable();
            contextType = atypeFactory.getAnnotatedType(var);
        } else if (parentTree.getKind() == Kind.VARIABLE) {
            contextType = atypeFactory.getAnnotatedType(parentTree);
        } else if (parentTree instanceof CompoundAssignmentTree) {
            Tree var = ((CompoundAssignmentTree) parentTree).getVariable();
            contextType = atypeFactory.getAnnotatedType(var);
        } else if (parentTree.getKind() == Kind.RETURN) {
            Tree methodTree = TreePathUtil.enclosingMethodOrLambda(path.getParentPath());
            if (methodTree.getKind() == Kind.METHOD) {
                AnnotatedExecutableType methodType = atypeFactory.getAnnotatedType((MethodTree) methodTree);
                contextType = methodType.getReturnType();
            }
        } else if (parentTree.getKind() == Kind.METHOD_INVOCATION && useAssignmentContext) {
            MethodInvocationTree methodInvocationTree = (MethodInvocationTree) parentTree;
            useAssignmentContext = false;
            AnnotatedExecutableType m;
            try {
                if (atypeFactory.shouldCache && methodInvocationToType.containsKey(methodInvocationTree)) {
                    m = methodInvocationToType.get(methodInvocationTree);
                } else {
                    m = atypeFactory.methodFromUse(methodInvocationTree).executableType;
                    if (atypeFactory.shouldCache) {
                        methodInvocationToType.put(methodInvocationTree, m);
                    }
                }
            } finally {
                useAssignmentContext = true;
            }
            for (int i = 0; i < m.getParameterTypes().size(); i++) {
                // Tree must be exactly the same.
                @SuppressWarnings("interning") boolean foundArgument = methodInvocationTree.getArguments().get(i) == tree;
                if (foundArgument) {
                    contextType = m.getParameterTypes().get(i);
                    break;
                }
            }
        }
    }
    Set<? extends AnnotationMirror> post;
    if (contextType instanceof AnnotatedArrayType) {
        AnnotatedTypeMirror contextComponentType = ((AnnotatedArrayType) contextType).getComponentType();
        // Only compare the qualifiers that existed in the array type.
        // Defaulting wasn't performed yet, so prev might have fewer qualifiers than
        // contextComponentType, which would cause a failure.
        // TODO: better solution?
        boolean prevIsSubtype = true;
        for (AnnotationMirror am : prev) {
            if (contextComponentType.isAnnotatedInHierarchy(am) && !this.qualHierarchy.isSubtype(am, contextComponentType.getAnnotationInHierarchy(am))) {
                prevIsSubtype = false;
            }
        }
        // It fails for array initializer expressions. Those should be handled nicer.
        if (contextComponentType.getKind() == componentType.getKind() && (prev.isEmpty() || (!contextComponentType.getAnnotations().isEmpty() && prevIsSubtype))) {
            post = contextComponentType.getAnnotations();
        } else {
            // The type of the array initializers is incompatible with the context type!
            // Somebody else will complain.
            post = prev;
        }
    } else {
        // No context is available - simply use what we have.
        post = prev;
    }
    // TODO (issue #599): This only works at the top level.  It should work at all levels of
    // the array.
    addAnnoOrBound(componentType, post);
    return null;
}
Also used : MethodTree(com.sun.source.tree.MethodTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType) AnnotationMirror(javax.lang.model.element.AnnotationMirror) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) TreePath(com.sun.source.util.TreePath) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ExpressionTree(com.sun.source.tree.ExpressionTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) MethodTree(com.sun.source.tree.MethodTree) BinaryTree(com.sun.source.tree.BinaryTree) UnaryTree(com.sun.source.tree.UnaryTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) TypeCastTree(com.sun.source.tree.TypeCastTree) NewArrayTree(com.sun.source.tree.NewArrayTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) AssignmentTree(com.sun.source.tree.AssignmentTree)

Example 18 with NewArrayTree

use of com.sun.source.tree.NewArrayTree in project checker-framework by typetools.

the class JavaExpression method fromTree.

/**
 * Converts a javac {@link ExpressionTree} to a CF JavaExpression. The result might contain {@link
 * Unknown}.
 *
 * <p>We ignore operations such as widening and narrowing when computing the JavaExpression.
 *
 * @param tree a javac tree
 * @return a JavaExpression for the given javac tree
 */
public static JavaExpression fromTree(ExpressionTree tree) {
    JavaExpression result;
    switch(tree.getKind()) {
        case ARRAY_ACCESS:
            ArrayAccessTree a = (ArrayAccessTree) tree;
            JavaExpression arrayAccessExpression = fromTree(a.getExpression());
            JavaExpression index = fromTree(a.getIndex());
            result = new ArrayAccess(TreeUtils.typeOf(a), arrayAccessExpression, index);
            break;
        case BOOLEAN_LITERAL:
        case CHAR_LITERAL:
        case DOUBLE_LITERAL:
        case FLOAT_LITERAL:
        case INT_LITERAL:
        case LONG_LITERAL:
        case NULL_LITERAL:
        case STRING_LITERAL:
            LiteralTree vn = (LiteralTree) tree;
            result = new ValueLiteral(TreeUtils.typeOf(tree), vn.getValue());
            break;
        case NEW_ARRAY:
            NewArrayTree newArrayTree = (NewArrayTree) tree;
            List<@Nullable JavaExpression> dimensions;
            if (newArrayTree.getDimensions() == null) {
                dimensions = Collections.emptyList();
            } else {
                dimensions = new ArrayList<>(newArrayTree.getDimensions().size());
                for (ExpressionTree dimension : newArrayTree.getDimensions()) {
                    dimensions.add(fromTree(dimension));
                }
            }
            List<JavaExpression> initializers;
            if (newArrayTree.getInitializers() == null) {
                initializers = Collections.emptyList();
            } else {
                initializers = new ArrayList<>(newArrayTree.getInitializers().size());
                for (ExpressionTree initializer : newArrayTree.getInitializers()) {
                    initializers.add(fromTree(initializer));
                }
            }
            result = new ArrayCreation(TreeUtils.typeOf(tree), dimensions, initializers);
            break;
        case METHOD_INVOCATION:
            MethodInvocationTree mn = (MethodInvocationTree) tree;
            assert TreeUtils.isUseOfElement(mn) : "@AssumeAssertion(nullness): tree kind";
            ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn);
            // Note that the method might be nondeterministic.
            List<JavaExpression> parameters = CollectionsPlume.mapList(JavaExpression::fromTree, mn.getArguments());
            JavaExpression methodReceiver;
            if (ElementUtils.isStatic(invokedMethod)) {
                @SuppressWarnings(// enclosingTypeElement(ExecutableElement): @NonNull
                "nullness:assignment") @NonNull TypeElement methodType = ElementUtils.enclosingTypeElement(invokedMethod);
                methodReceiver = new ClassName(methodType.asType());
            } else {
                methodReceiver = getReceiver(mn);
            }
            TypeMirror resultType = TreeUtils.typeOf(mn);
            result = new MethodCall(resultType, invokedMethod, methodReceiver, parameters);
            break;
        case MEMBER_SELECT:
            result = fromMemberSelect((MemberSelectTree) tree);
            break;
        case IDENTIFIER:
            IdentifierTree identifierTree = (IdentifierTree) tree;
            TypeMirror typeOfId = TreeUtils.typeOf(identifierTree);
            Name identifierName = identifierTree.getName();
            if (identifierName.contentEquals("this") || identifierName.contentEquals("super")) {
                result = new ThisReference(typeOfId);
                break;
            }
            assert TreeUtils.isUseOfElement(identifierTree) : "@AssumeAssertion(nullness): tree kind";
            Element ele = TreeUtils.elementFromUse(identifierTree);
            if (ElementUtils.isTypeElement(ele)) {
                result = new ClassName(ele.asType());
                break;
            }
            result = fromVariableElement(typeOfId, ele);
            break;
        case UNARY_PLUS:
            return fromTree(((UnaryTree) tree).getExpression());
        case BITWISE_COMPLEMENT:
        case LOGICAL_COMPLEMENT:
        case POSTFIX_DECREMENT:
        case POSTFIX_INCREMENT:
        case PREFIX_DECREMENT:
        case PREFIX_INCREMENT:
        case UNARY_MINUS:
            JavaExpression operand = fromTree(((UnaryTree) tree).getExpression());
            return new UnaryOperation(TreeUtils.typeOf(tree), tree.getKind(), operand);
        case CONDITIONAL_AND:
        case CONDITIONAL_OR:
        case DIVIDE:
        case EQUAL_TO:
        case GREATER_THAN:
        case GREATER_THAN_EQUAL:
        case LEFT_SHIFT:
        case LESS_THAN:
        case LESS_THAN_EQUAL:
        case MINUS:
        case MULTIPLY:
        case NOT_EQUAL_TO:
        case OR:
        case PLUS:
        case REMAINDER:
        case RIGHT_SHIFT:
        case UNSIGNED_RIGHT_SHIFT:
        case XOR:
            BinaryTree binaryTree = (BinaryTree) tree;
            JavaExpression left = fromTree(binaryTree.getLeftOperand());
            JavaExpression right = fromTree(binaryTree.getRightOperand());
            return new BinaryOperation(TreeUtils.typeOf(tree), tree.getKind(), left, right);
        default:
            result = null;
    }
    if (result == null) {
        result = new Unknown(tree);
    }
    return result;
}
Also used : ArrayAccessTree(com.sun.source.tree.ArrayAccessTree) ExecutableElement(javax.lang.model.element.ExecutableElement) MemberSelectTree(com.sun.source.tree.MemberSelectTree) TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) BinaryTree(com.sun.source.tree.BinaryTree) IdentifierTree(com.sun.source.tree.IdentifierTree) LiteralTree(com.sun.source.tree.LiteralTree) Name(javax.lang.model.element.Name) TypeMirror(javax.lang.model.type.TypeMirror) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) NonNull(org.checkerframework.checker.nullness.qual.NonNull) ExpressionTree(com.sun.source.tree.ExpressionTree) TypeElement(javax.lang.model.element.TypeElement) NewArrayTree(com.sun.source.tree.NewArrayTree)

Example 19 with NewArrayTree

use of com.sun.source.tree.NewArrayTree in project checker-framework by typetools.

the class AnnotatedTypeFactory method getFunctionalInterfaceType.

/**
 * Get the AnnotatedDeclaredType for the FunctionalInterface from assignment context of the method
 * reference or lambda expression which may be a variable assignment, a method call, or a cast.
 *
 * <p>The assignment context is not always correct, so we must search up the AST. It will
 * recursively search for lambdas nested in lambdas.
 *
 * @param tree the tree of the lambda or method reference
 * @return the functional interface type or an uninferred type argument
 */
private AnnotatedTypeMirror getFunctionalInterfaceType(Tree tree) {
    Tree parentTree = getPath(tree).getParentPath().getLeaf();
    switch(parentTree.getKind()) {
        case PARENTHESIZED:
            return getFunctionalInterfaceType(parentTree);
        case TYPE_CAST:
            TypeCastTree cast = (TypeCastTree) parentTree;
            assert isFunctionalInterface(trees.getTypeMirror(getPath(cast.getType())), parentTree, tree);
            AnnotatedTypeMirror castATM = getAnnotatedType(cast.getType());
            if (castATM.getKind() == TypeKind.INTERSECTION) {
                AnnotatedIntersectionType itype = (AnnotatedIntersectionType) castATM;
                for (AnnotatedTypeMirror t : itype.directSupertypes()) {
                    if (TypesUtils.isFunctionalInterface(t.getUnderlyingType(), getProcessingEnv())) {
                        return t;
                    }
                }
                // and would have raised an error already.
                throw new BugInCF("Expected the type of a cast tree in an assignment context to contain a functional" + " interface bound. Found type: %s for tree: %s in lambda tree: %s", castATM, cast, tree);
            }
            return castATM;
        case NEW_CLASS:
            NewClassTree newClass = (NewClassTree) parentTree;
            int indexOfLambda = newClass.getArguments().indexOf(tree);
            ParameterizedExecutableType con = this.constructorFromUse(newClass);
            AnnotatedTypeMirror constructorParam = AnnotatedTypes.getAnnotatedTypeMirrorOfParameter(con.executableType, indexOfLambda);
            assert isFunctionalInterface(constructorParam.getUnderlyingType(), parentTree, tree);
            return constructorParam;
        case NEW_ARRAY:
            NewArrayTree newArray = (NewArrayTree) parentTree;
            AnnotatedArrayType newArrayATM = getAnnotatedType(newArray);
            AnnotatedTypeMirror elementATM = newArrayATM.getComponentType();
            assert isFunctionalInterface(elementATM.getUnderlyingType(), parentTree, tree);
            return elementATM;
        case METHOD_INVOCATION:
            MethodInvocationTree method = (MethodInvocationTree) parentTree;
            int index = method.getArguments().indexOf(tree);
            ParameterizedExecutableType exe = this.methodFromUse(method);
            AnnotatedTypeMirror param = AnnotatedTypes.getAnnotatedTypeMirrorOfParameter(exe.executableType, index);
            if (param.getKind() == TypeKind.WILDCARD) {
                // param is an uninferred wildcard.
                TypeMirror typeMirror = TreeUtils.typeOf(tree);
                param = AnnotatedTypeMirror.createType(typeMirror, this, false);
                addDefaultAnnotations(param);
            }
            assert isFunctionalInterface(param.getUnderlyingType(), parentTree, tree);
            return param;
        case VARIABLE:
            VariableTree varTree = (VariableTree) parentTree;
            assert isFunctionalInterface(TreeUtils.typeOf(varTree), parentTree, tree);
            return getAnnotatedType(varTree.getType());
        case ASSIGNMENT:
            AssignmentTree assignmentTree = (AssignmentTree) parentTree;
            assert isFunctionalInterface(TreeUtils.typeOf(assignmentTree), parentTree, tree);
            return getAnnotatedType(assignmentTree.getVariable());
        case RETURN:
            Tree enclosing = TreePathUtil.enclosingOfKind(getPath(parentTree), new HashSet<>(Arrays.asList(Tree.Kind.METHOD, Tree.Kind.LAMBDA_EXPRESSION)));
            if (enclosing.getKind() == Tree.Kind.METHOD) {
                MethodTree enclosingMethod = (MethodTree) enclosing;
                return getAnnotatedType(enclosingMethod.getReturnType());
            } else {
                LambdaExpressionTree enclosingLambda = (LambdaExpressionTree) enclosing;
                AnnotatedExecutableType methodExe = getFunctionTypeFromTree(enclosingLambda);
                return methodExe.getReturnType();
            }
        case LAMBDA_EXPRESSION:
            LambdaExpressionTree enclosingLambda = (LambdaExpressionTree) parentTree;
            AnnotatedExecutableType methodExe = getFunctionTypeFromTree(enclosingLambda);
            return methodExe.getReturnType();
        case CONDITIONAL_EXPRESSION:
            ConditionalExpressionTree conditionalExpressionTree = (ConditionalExpressionTree) parentTree;
            final AnnotatedTypeMirror falseType = getAnnotatedType(conditionalExpressionTree.getFalseExpression());
            final AnnotatedTypeMirror trueType = getAnnotatedType(conditionalExpressionTree.getTrueExpression());
            // Known cases where we must use LUB because falseType/trueType will not be equal:
            // a) when one of the types is a type variable that extends a functional interface
            // or extends a type variable that extends a functional interface
            // b) When one of the two sides of the expression is a reference to a sub-interface.
            // e.g.   interface ConsumeStr {
            // public void consume(String s)
            // }
            // interface SubConsumer extends ConsumeStr {
            // default void someOtherMethod() { ... }
            // }
            // SubConsumer s = ...;
            // ConsumeStr stringConsumer = (someCondition) ? s : System.out::println;
            AnnotatedTypeMirror conditionalType = AnnotatedTypes.leastUpperBound(this, trueType, falseType);
            assert isFunctionalInterface(conditionalType.getUnderlyingType(), parentTree, tree);
            return conditionalType;
        default:
            throw new BugInCF("Could not find functional interface from assignment context. " + "Unexpected tree type: " + parentTree.getKind() + " For lambda tree: " + tree);
    }
}
Also used : TypeCastTree(com.sun.source.tree.TypeCastTree) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) NewClassTree(com.sun.source.tree.NewClassTree) BugInCF(org.checkerframework.javacutil.BugInCF) AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotatedIntersectionType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedIntersectionType) NewArrayTree(com.sun.source.tree.NewArrayTree) TypeMirror(javax.lang.model.type.TypeMirror) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) TypeCastTree(com.sun.source.tree.TypeCastTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ReturnTree(com.sun.source.tree.ReturnTree) VariableTree(com.sun.source.tree.VariableTree) NewClassTree(com.sun.source.tree.NewClassTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) NewArrayTree(com.sun.source.tree.NewArrayTree) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) AnnotationTree(com.sun.source.tree.AnnotationTree) MethodTree(com.sun.source.tree.MethodTree) BinaryTree(com.sun.source.tree.BinaryTree) ClassTree(com.sun.source.tree.ClassTree) MemberReferenceTree(com.sun.source.tree.MemberReferenceTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) AssignmentTree(com.sun.source.tree.AssignmentTree)

Example 20 with NewArrayTree

use of com.sun.source.tree.NewArrayTree in project checker-framework by typetools.

the class CFGTranslationPhaseOne method convertCallArguments.

/**
 * Given a method element and as list of argument expressions, return a list of {@link Node}s
 * representing the arguments converted for a call of the method. This method applies to both
 * method invocations and constructor calls.
 *
 * @param method an ExecutableElement representing a method to be called
 * @param actualExprs a List of argument expressions to a call
 * @return a List of {@link Node}s representing arguments after conversions required by a call to
 *     this method
 */
protected List<Node> convertCallArguments(ExecutableElement method, List<? extends ExpressionTree> actualExprs) {
    // NOTE: It is important to convert one method argument before generating CFG nodes for the next
    // argument, since label binding expects nodes to be generated in execution order.  Therefore,
    // this method first determines which conversions need to be applied and then iterates over the
    // actual arguments.
    List<? extends VariableElement> formals = method.getParameters();
    int numFormals = formals.size();
    ArrayList<Node> convertedNodes = new ArrayList<>(numFormals);
    int numActuals = actualExprs.size();
    if (method.isVarArgs()) {
        // Create a new array argument if the actuals outnumber the formals, or if the last actual is
        // not assignable to the last formal.
        int lastArgIndex = numFormals - 1;
        TypeMirror lastParamType = formals.get(lastArgIndex).asType();
        if (numActuals == numFormals && types.isAssignable(TreeUtils.typeOf(actualExprs.get(numActuals - 1)), lastParamType)) {
            // invocation conversion to all arguments.
            for (int i = 0; i < numActuals; i++) {
                Node actualVal = scan(actualExprs.get(i), null);
                if (actualVal == null) {
                    throw new BugInCF("CFGBuilder: scan returned null for %s [%s]", actualExprs.get(i), actualExprs.get(i).getClass());
                }
                convertedNodes.add(methodInvocationConvert(actualVal, formals.get(i).asType()));
            }
        } else {
            assert lastParamType instanceof ArrayType : "variable argument formal must be an array";
            // to initialize an array.
            for (int i = 0; i < lastArgIndex; i++) {
                Node actualVal = scan(actualExprs.get(i), null);
                convertedNodes.add(methodInvocationConvert(actualVal, formals.get(i).asType()));
            }
            TypeMirror elemType = ((ArrayType) lastParamType).getComponentType();
            List<ExpressionTree> inits = new ArrayList<>(numActuals - lastArgIndex);
            List<Node> initializers = new ArrayList<>(numActuals - lastArgIndex);
            for (int i = lastArgIndex; i < numActuals; i++) {
                inits.add(actualExprs.get(i));
                Node actualVal = scan(actualExprs.get(i), null);
                initializers.add(assignConvert(actualVal, elemType));
            }
            NewArrayTree wrappedVarargs = treeBuilder.buildNewArray(elemType, inits);
            handleArtificialTree(wrappedVarargs);
            Node lastArgument = new ArrayCreationNode(wrappedVarargs, lastParamType, /*dimensions=*/
            Collections.emptyList(), initializers);
            extendWithNode(lastArgument);
            convertedNodes.add(lastArgument);
        }
    } else {
        for (int i = 0; i < numActuals; i++) {
            Node actualVal = scan(actualExprs.get(i), null);
            convertedNodes.add(methodInvocationConvert(actualVal, formals.get(i).asType()));
        }
    }
    return convertedNodes;
}
Also used : NumericalMultiplicationNode(org.checkerframework.dataflow.cfg.node.NumericalMultiplicationNode) ArrayCreationNode(org.checkerframework.dataflow.cfg.node.ArrayCreationNode) ValueLiteralNode(org.checkerframework.dataflow.cfg.node.ValueLiteralNode) StringConversionNode(org.checkerframework.dataflow.cfg.node.StringConversionNode) UnsignedRightShiftNode(org.checkerframework.dataflow.cfg.node.UnsignedRightShiftNode) LeftShiftNode(org.checkerframework.dataflow.cfg.node.LeftShiftNode) PrimitiveTypeNode(org.checkerframework.dataflow.cfg.node.PrimitiveTypeNode) FloatLiteralNode(org.checkerframework.dataflow.cfg.node.FloatLiteralNode) LessThanNode(org.checkerframework.dataflow.cfg.node.LessThanNode) BitwiseOrNode(org.checkerframework.dataflow.cfg.node.BitwiseOrNode) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) NarrowingConversionNode(org.checkerframework.dataflow.cfg.node.NarrowingConversionNode) EqualToNode(org.checkerframework.dataflow.cfg.node.EqualToNode) NumericalPlusNode(org.checkerframework.dataflow.cfg.node.NumericalPlusNode) ConditionalAndNode(org.checkerframework.dataflow.cfg.node.ConditionalAndNode) VariableDeclarationNode(org.checkerframework.dataflow.cfg.node.VariableDeclarationNode) ClassDeclarationNode(org.checkerframework.dataflow.cfg.node.ClassDeclarationNode) IntegerDivisionNode(org.checkerframework.dataflow.cfg.node.IntegerDivisionNode) AssertionErrorNode(org.checkerframework.dataflow.cfg.node.AssertionErrorNode) InstanceOfNode(org.checkerframework.dataflow.cfg.node.InstanceOfNode) BooleanLiteralNode(org.checkerframework.dataflow.cfg.node.BooleanLiteralNode) ThisNode(org.checkerframework.dataflow.cfg.node.ThisNode) AssignmentNode(org.checkerframework.dataflow.cfg.node.AssignmentNode) NullLiteralNode(org.checkerframework.dataflow.cfg.node.NullLiteralNode) ArrayTypeNode(org.checkerframework.dataflow.cfg.node.ArrayTypeNode) LambdaResultExpressionNode(org.checkerframework.dataflow.cfg.node.LambdaResultExpressionNode) IntegerRemainderNode(org.checkerframework.dataflow.cfg.node.IntegerRemainderNode) FieldAccessNode(org.checkerframework.dataflow.cfg.node.FieldAccessNode) ConditionalOrNode(org.checkerframework.dataflow.cfg.node.ConditionalOrNode) NotEqualNode(org.checkerframework.dataflow.cfg.node.NotEqualNode) BitwiseXorNode(org.checkerframework.dataflow.cfg.node.BitwiseXorNode) ArrayAccessNode(org.checkerframework.dataflow.cfg.node.ArrayAccessNode) ExplicitThisNode(org.checkerframework.dataflow.cfg.node.ExplicitThisNode) StringConcatenateNode(org.checkerframework.dataflow.cfg.node.StringConcatenateNode) NullChkNode(org.checkerframework.dataflow.cfg.node.NullChkNode) CharacterLiteralNode(org.checkerframework.dataflow.cfg.node.CharacterLiteralNode) FloatingDivisionNode(org.checkerframework.dataflow.cfg.node.FloatingDivisionNode) FunctionalInterfaceNode(org.checkerframework.dataflow.cfg.node.FunctionalInterfaceNode) StringConcatenateAssignmentNode(org.checkerframework.dataflow.cfg.node.StringConcatenateAssignmentNode) TypeCastNode(org.checkerframework.dataflow.cfg.node.TypeCastNode) MethodAccessNode(org.checkerframework.dataflow.cfg.node.MethodAccessNode) WideningConversionNode(org.checkerframework.dataflow.cfg.node.WideningConversionNode) LongLiteralNode(org.checkerframework.dataflow.cfg.node.LongLiteralNode) MarkerNode(org.checkerframework.dataflow.cfg.node.MarkerNode) ImplicitThisNode(org.checkerframework.dataflow.cfg.node.ImplicitThisNode) FloatingRemainderNode(org.checkerframework.dataflow.cfg.node.FloatingRemainderNode) ClassNameNode(org.checkerframework.dataflow.cfg.node.ClassNameNode) ObjectCreationNode(org.checkerframework.dataflow.cfg.node.ObjectCreationNode) PackageNameNode(org.checkerframework.dataflow.cfg.node.PackageNameNode) DoubleLiteralNode(org.checkerframework.dataflow.cfg.node.DoubleLiteralNode) SuperNode(org.checkerframework.dataflow.cfg.node.SuperNode) IntegerLiteralNode(org.checkerframework.dataflow.cfg.node.IntegerLiteralNode) SignedRightShiftNode(org.checkerframework.dataflow.cfg.node.SignedRightShiftNode) ThrowNode(org.checkerframework.dataflow.cfg.node.ThrowNode) GreaterThanOrEqualNode(org.checkerframework.dataflow.cfg.node.GreaterThanOrEqualNode) StringLiteralNode(org.checkerframework.dataflow.cfg.node.StringLiteralNode) TernaryExpressionNode(org.checkerframework.dataflow.cfg.node.TernaryExpressionNode) BitwiseAndNode(org.checkerframework.dataflow.cfg.node.BitwiseAndNode) ParameterizedTypeNode(org.checkerframework.dataflow.cfg.node.ParameterizedTypeNode) CaseNode(org.checkerframework.dataflow.cfg.node.CaseNode) SwitchExpressionNode(org.checkerframework.dataflow.cfg.node.SwitchExpressionNode) NumericalAdditionNode(org.checkerframework.dataflow.cfg.node.NumericalAdditionNode) NumericalSubtractionNode(org.checkerframework.dataflow.cfg.node.NumericalSubtractionNode) BitwiseComplementNode(org.checkerframework.dataflow.cfg.node.BitwiseComplementNode) ConditionalNotNode(org.checkerframework.dataflow.cfg.node.ConditionalNotNode) NumericalMinusNode(org.checkerframework.dataflow.cfg.node.NumericalMinusNode) ReturnNode(org.checkerframework.dataflow.cfg.node.ReturnNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) GreaterThanNode(org.checkerframework.dataflow.cfg.node.GreaterThanNode) LessThanOrEqualNode(org.checkerframework.dataflow.cfg.node.LessThanOrEqualNode) SynchronizedNode(org.checkerframework.dataflow.cfg.node.SynchronizedNode) Node(org.checkerframework.dataflow.cfg.node.Node) ArrayList(java.util.ArrayList) BugInCF(org.checkerframework.javacutil.BugInCF) ArrayCreationNode(org.checkerframework.dataflow.cfg.node.ArrayCreationNode) ArrayType(javax.lang.model.type.ArrayType) TypeMirror(javax.lang.model.type.TypeMirror) NewArrayTree(com.sun.source.tree.NewArrayTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Aggregations

NewArrayTree (com.sun.source.tree.NewArrayTree)21 ExpressionTree (com.sun.source.tree.ExpressionTree)19 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)12 Tree (com.sun.source.tree.Tree)11 AssignmentTree (com.sun.source.tree.AssignmentTree)10 CompoundAssignmentTree (com.sun.source.tree.CompoundAssignmentTree)10 MemberSelectTree (com.sun.source.tree.MemberSelectTree)10 BinaryTree (com.sun.source.tree.BinaryTree)9 ArrayAccessTree (com.sun.source.tree.ArrayAccessTree)8 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)8 IdentifierTree (com.sun.source.tree.IdentifierTree)8 LiteralTree (com.sun.source.tree.LiteralTree)8 MethodTree (com.sun.source.tree.MethodTree)8 NewClassTree (com.sun.source.tree.NewClassTree)8 TypeCastTree (com.sun.source.tree.TypeCastTree)8 VariableTree (com.sun.source.tree.VariableTree)8 ClassTree (com.sun.source.tree.ClassTree)7 ParameterizedTypeTree (com.sun.source.tree.ParameterizedTypeTree)6 ReturnTree (com.sun.source.tree.ReturnTree)6 ExecutableElement (javax.lang.model.element.ExecutableElement)6