Search in sources :

Example 11 with AnnotatedArrayType

use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType 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
 */
private AnnotatedDeclaredType 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 (AnnotatedDeclaredType) t;
                    }
                }
                // We should never reach here: isFunctionalInterface performs the same check
                // and would have raised an error already.
                ErrorReporter.errorAbort(String.format("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 (AnnotatedDeclaredType) castATM;
        case NEW_CLASS:
            NewClassTree newClass = (NewClassTree) parentTree;
            int indexOfLambda = newClass.getArguments().indexOf(tree);
            Pair<AnnotatedExecutableType, List<AnnotatedTypeMirror>> con = this.constructorFromUse(newClass);
            AnnotatedTypeMirror constructorParam = AnnotatedTypes.getAnnotatedTypeMirrorOfParameter(con.first, indexOfLambda);
            assert isFunctionalInterface(constructorParam.getUnderlyingType(), parentTree, tree);
            return (AnnotatedDeclaredType) constructorParam;
        case NEW_ARRAY:
            NewArrayTree newArray = (NewArrayTree) parentTree;
            AnnotatedArrayType newArrayATM = getAnnotatedType(newArray);
            AnnotatedTypeMirror elementATM = newArrayATM.getComponentType();
            assert isFunctionalInterface(elementATM.getUnderlyingType(), parentTree, tree);
            return (AnnotatedDeclaredType) elementATM;
        case METHOD_INVOCATION:
            MethodInvocationTree method = (MethodInvocationTree) parentTree;
            int index = method.getArguments().indexOf(tree);
            Pair<AnnotatedExecutableType, List<AnnotatedTypeMirror>> exe = this.methodFromUse(method);
            AnnotatedTypeMirror param = AnnotatedTypes.getAnnotatedTypeMirrorOfParameter(exe.first, 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 (AnnotatedDeclaredType) param;
        case VARIABLE:
            VariableTree varTree = (VariableTree) parentTree;
            assert isFunctionalInterface(TreeUtils.typeOf(varTree), parentTree, tree);
            return (AnnotatedDeclaredType) getAnnotatedType(varTree.getType());
        case ASSIGNMENT:
            AssignmentTree assignmentTree = (AssignmentTree) parentTree;
            assert isFunctionalInterface(TreeUtils.typeOf(assignmentTree), parentTree, tree);
            return (AnnotatedDeclaredType) getAnnotatedType(assignmentTree.getVariable());
        case RETURN:
            Tree enclosing = TreeUtils.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 (AnnotatedDeclaredType) getAnnotatedType(enclosingMethod.getReturnType());
            } else {
                LambdaExpressionTree enclosingLambda = (LambdaExpressionTree) enclosing;
                Pair<AnnotatedDeclaredType, AnnotatedExecutableType> result = getFnInterfaceFromTree(enclosingLambda);
                AnnotatedExecutableType methodExe = result.second;
                return (AnnotatedDeclaredType) methodExe.getReturnType();
            }
        case LAMBDA_EXPRESSION:
            LambdaExpressionTree enclosingLambda = (LambdaExpressionTree) parentTree;
            Pair<AnnotatedDeclaredType, AnnotatedExecutableType> result = getFnInterfaceFromTree(enclosingLambda);
            AnnotatedExecutableType methodExe = result.second;
            return (AnnotatedDeclaredType) 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 (AnnotatedDeclaredType) conditionalType;
        default:
            ErrorReporter.errorAbort("Could not find functional interface from assignment context. " + "Unexpected tree type: " + parentTree.getKind() + " For lambda tree: " + tree);
            return null;
    }
}
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) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) 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) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) 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) IdentifierTree(com.sun.source.tree.IdentifierTree) NewArrayTree(com.sun.source.tree.NewArrayTree) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) AnnotationTree(com.sun.source.tree.AnnotationTree) MethodTree(com.sun.source.tree.MethodTree) ClassTree(com.sun.source.tree.ClassTree) MemberReferenceTree(com.sun.source.tree.MemberReferenceTree) ArrayList(java.util.ArrayList) List(java.util.List) AssignmentTree(com.sun.source.tree.AssignmentTree)

Example 12 with AnnotatedArrayType

use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType in project checker-framework by typetools.

the class TypeFromExpressionVisitor method annotateArrayAsArray.

private void annotateArrayAsArray(AnnotatedArrayType result, NewArrayTree node, AnnotatedTypeFactory f) {
    // Copy annotations from the type.
    AnnotatedTypeMirror treeElem = f.fromTypeTree(node.getType());
    boolean hasInit = node.getInitializers() != null;
    AnnotatedTypeMirror typeElem = descendBy(result, hasInit ? 1 : node.getDimensions().size());
    while (true) {
        typeElem.addAnnotations(treeElem.getAnnotations());
        if (!(treeElem instanceof AnnotatedArrayType))
            break;
        assert typeElem instanceof AnnotatedArrayType;
        treeElem = ((AnnotatedArrayType) treeElem).getComponentType();
        typeElem = ((AnnotatedArrayType) typeElem).getComponentType();
    }
    // Add all dimension annotations.
    int idx = 0;
    AnnotatedTypeMirror level = result;
    while (level.getKind() == TypeKind.ARRAY) {
        AnnotatedArrayType array = (AnnotatedArrayType) level;
        List<? extends AnnotationMirror> annos = TreeUtils.annotationsFromArrayCreation(node, idx++);
        array.addAnnotations(annos);
        level = array.getComponentType();
    }
    // Add top-level annotations.
    result.addAnnotations(TreeUtils.annotationsFromArrayCreation(node, -1));
}
Also used : AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType)

Example 13 with AnnotatedArrayType

use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType 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();
    Collection<? extends AnnotationMirror> prev = null;
    if (tree.getInitializers() != null && tree.getInitializers().size() != 0) {
        for (ExpressionTree init : tree.getInitializers()) {
            AnnotatedTypeMirror initType = atypeFactory.getAnnotatedType(init);
            // initType might be a typeVariable, so use effectiveAnnotations.
            Collection<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";
    Pair<Tree, AnnotatedTypeMirror> context = atypeFactory.getVisitorState().getAssignmentContext();
    Collection<? extends AnnotationMirror> post;
    if (context != null && context.second != null && context.second instanceof AnnotatedArrayType) {
        AnnotatedTypeMirror contextComponentType = ((AnnotatedArrayType) context.second).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;
    }
    componentType.addMissingAnnotations(post);
    return null;
}
Also used : AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType) AnnotationMirror(javax.lang.model.element.AnnotationMirror) ExpressionTree(com.sun.source.tree.ExpressionTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) ExpressionTree(com.sun.source.tree.ExpressionTree) BinaryTree(com.sun.source.tree.BinaryTree) UnaryTree(com.sun.source.tree.UnaryTree) TypeCastTree(com.sun.source.tree.TypeCastTree) NewArrayTree(com.sun.source.tree.NewArrayTree) Tree(com.sun.source.tree.Tree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 14 with AnnotatedArrayType

use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType in project checker-framework by typetools.

the class AnnotatedTypes method containsModifierImpl.

/*
     * For type variables we might hit the same type again. We keep a list of visited types.
     */
private static boolean containsModifierImpl(AnnotatedTypeMirror type, AnnotationMirror modifier, List<AnnotatedTypeMirror> visited) {
    boolean found = type.hasAnnotation(modifier);
    boolean vis = visited.contains(type);
    visited.add(type);
    if (!found && !vis) {
        if (type.getKind() == TypeKind.DECLARED) {
            AnnotatedDeclaredType declaredType = (AnnotatedDeclaredType) type;
            for (AnnotatedTypeMirror typeMirror : declaredType.getTypeArguments()) {
                found |= containsModifierImpl(typeMirror, modifier, visited);
                if (found) {
                    break;
                }
            }
        } else if (type.getKind() == TypeKind.ARRAY) {
            AnnotatedArrayType arrayType = (AnnotatedArrayType) type;
            found = containsModifierImpl(arrayType.getComponentType(), modifier, visited);
        } else if (type.getKind() == TypeKind.TYPEVAR) {
            AnnotatedTypeVariable atv = (AnnotatedTypeVariable) type;
            if (atv.getUpperBound() != null) {
                found = containsModifierImpl(atv.getUpperBound(), modifier, visited);
            }
            if (!found && atv.getLowerBound() != null) {
                found = containsModifierImpl(atv.getLowerBound(), modifier, visited);
            }
        } else if (type.getKind() == TypeKind.WILDCARD) {
            AnnotatedWildcardType awc = (AnnotatedWildcardType) type;
            if (awc.getExtendsBound() != null) {
                found = containsModifierImpl(awc.getExtendsBound(), modifier, visited);
            }
            if (!found && awc.getSuperBound() != null) {
                found = containsModifierImpl(awc.getSuperBound(), modifier, visited);
            }
        }
    }
    return found;
}
Also used : AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) AnnotatedWildcardType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable)

Example 15 with AnnotatedArrayType

use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType in project checker-framework by typetools.

the class AnnotatedTypes method expandVarArgs.

/**
 * Returns the method parameters for the invoked method, with the same number of arguments
 * passed in the methodInvocation tree.
 *
 * <p>If the invoked method is not a vararg method or it is a vararg method but the invocation
 * passes an array to the vararg parameter, it would simply return the method parameters.
 *
 * <p>Otherwise, it would return the list of parameters as if the vararg is expanded to match
 * the size of the passed arguments.
 *
 * @param method the method's type
 * @param args the arguments to the method invocation
 * @return the types that the method invocation arguments need to be subtype of
 */
public static List<AnnotatedTypeMirror> expandVarArgs(AnnotatedTypeFactory atypeFactory, AnnotatedExecutableType method, List<? extends ExpressionTree> args) {
    List<AnnotatedTypeMirror> parameters = method.getParameterTypes();
    if (!method.getElement().isVarArgs()) {
        return parameters;
    }
    AnnotatedArrayType varargs = (AnnotatedArrayType) parameters.get(parameters.size() - 1);
    if (parameters.size() == args.size()) {
        // Check if one sent an element or an array
        AnnotatedTypeMirror lastArg = atypeFactory.getAnnotatedType(args.get(args.size() - 1));
        if (lastArg.getKind() == TypeKind.ARRAY && getArrayDepth(varargs) == getArrayDepth((AnnotatedArrayType) lastArg)) {
            return parameters;
        }
    }
    parameters = new ArrayList<>(parameters.subList(0, parameters.size() - 1));
    for (int i = args.size() - parameters.size(); i > 0; --i) {
        parameters.add(varargs.getComponentType());
    }
    return parameters;
}
Also used : AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Aggregations

AnnotatedArrayType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType)23 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)15 AnnotatedDeclaredType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType)6 ExpressionTree (com.sun.source.tree.ExpressionTree)4 NewArrayTree (com.sun.source.tree.NewArrayTree)4 AnnotatedExecutableType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType)4 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)3 Tree (com.sun.source.tree.Tree)3 TypeCastTree (com.sun.source.tree.TypeCastTree)3 ArrayList (java.util.ArrayList)3 List (java.util.List)3 AnnotationMirror (javax.lang.model.element.AnnotationMirror)3 AnnotatedWildcardType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType)3 AnnotationTree (com.sun.source.tree.AnnotationTree)2 AssignmentTree (com.sun.source.tree.AssignmentTree)2 ClassTree (com.sun.source.tree.ClassTree)2 CompilationUnitTree (com.sun.source.tree.CompilationUnitTree)2 CompoundAssignmentTree (com.sun.source.tree.CompoundAssignmentTree)2 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)2 IdentifierTree (com.sun.source.tree.IdentifierTree)2