Search in sources :

Example 21 with AnnotatedExecutableType

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

the class AnnotatedTypeFactory method getCurrentMethodReceiver.

/**
 * Returns the receiver type of the current method being visited, and returns null if the
 * visited tree is not within a method or if that method has no receiver (e.g. a static method).
 *
 * <p>The method uses the parameter only if the most enclosing method cannot be found directly.
 *
 * @return receiver type of the most enclosing method being visited
 */
@Nullable
protected final AnnotatedDeclaredType getCurrentMethodReceiver(Tree tree) {
    AnnotatedDeclaredType res = visitorState.getMethodReceiver();
    if (res == null) {
        TreePath path = getPath(tree);
        if (path != null) {
            MethodTree enclosingMethod = TreeUtils.enclosingMethod(path);
            ClassTree enclosingClass = TreeUtils.enclosingClass(path);
            boolean found = false;
            for (Tree member : enclosingClass.getMembers()) {
                if (member.getKind() == Tree.Kind.METHOD) {
                    if (member == enclosingMethod) {
                        found = true;
                    }
                }
            }
            if (found && enclosingMethod != null) {
                AnnotatedExecutableType method = getAnnotatedType(enclosingMethod);
                res = method.getReceiverType();
            // TODO: three tests fail if one adds the following, which would make
            // sense, or not?
            // visitorState.setMethodReceiver(res);
            } else {
                // We are within an anonymous class or field initializer
                res = this.getAnnotatedType(enclosingClass);
            }
        }
    }
    return res;
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) TreePath(com.sun.source.util.TreePath) MethodTree(com.sun.source.tree.MethodTree) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) NewClassTree(com.sun.source.tree.NewClassTree) ClassTree(com.sun.source.tree.ClassTree) 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) Nullable(org.checkerframework.checker.nullness.qual.Nullable)

Example 22 with AnnotatedExecutableType

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

the class AnnotatedTypeFactory method methodFromUse.

/**
 * Determines the type of the invoked method based on the passed method invocation tree.
 *
 * <p>The returned method type has all type variables resolved, whether based on receiver type,
 * passed type parameters if any, and method invocation parameter.
 *
 * <p>Subclasses may override this method to customize inference of types or qualifiers based on
 * method invocation parameters.
 *
 * <p>As an implementation detail, this method depends on {@link
 * AnnotatedTypes#asMemberOf(Types, AnnotatedTypeFactory, AnnotatedTypeMirror, Element)}, and
 * customization based on receiver type should be in accordance to its specification.
 *
 * <p>The return type is a pair of the type of the invoked method and the (inferred) type
 * arguments. Note that neither the explicitly passed nor the inferred type arguments are
 * guaranteed to be subtypes of the corresponding upper bounds. See method {@link
 * org.checkerframework.common.basetype.BaseTypeVisitor#checkTypeArguments(Tree, List, List,
 * List)} for the checks of type argument well-formedness.
 *
 * <p>Note that "this" and "super" constructor invocations are also handled by this method.
 * Method {@link #constructorFromUse(NewClassTree)} is only used for a constructor invocation in
 * a "new" expression.
 *
 * @param tree the method invocation tree
 * @return the method type being invoked with tree and the (inferred) type arguments
 */
public Pair<AnnotatedExecutableType, List<AnnotatedTypeMirror>> methodFromUse(MethodInvocationTree tree) {
    ExecutableElement methodElt = TreeUtils.elementFromUse(tree);
    AnnotatedTypeMirror receiverType = getReceiverType(tree);
    Pair<AnnotatedExecutableType, List<AnnotatedTypeMirror>> mfuPair = methodFromUse(tree, methodElt, receiverType);
    if (checker.shouldResolveReflection() && reflectionResolver.isReflectiveMethodInvocation(tree)) {
        mfuPair = reflectionResolver.resolveReflectiveCall(this, tree, mfuPair);
    }
    AnnotatedExecutableType method = mfuPair.first;
    if (method.getReturnType().getKind() == TypeKind.WILDCARD && ((AnnotatedWildcardType) method.getReturnType()).isUninferredTypeArgument()) {
        // Get the correct Java type from the tree and use it as the upper bound of the
        // wildcard.
        TypeMirror tm = TreeUtils.typeOf(tree);
        AnnotatedTypeMirror t = toAnnotatedType(tm, false);
        AnnotatedWildcardType wildcard = (AnnotatedWildcardType) method.getReturnType();
        if (ignoreUninferredTypeArguments) {
            // remove the annotations so that default annotations are used instead.
            // (See call to addDefaultAnnotations below.)
            t.clearAnnotations();
        } else {
            t.replaceAnnotations(wildcard.getExtendsBound().getAnnotations());
        }
        wildcard.setExtendsBound(t);
        addDefaultAnnotations(wildcard);
    }
    return mfuPair;
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) TypeMirror(javax.lang.model.type.TypeMirror) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) List(java.util.List) AnnotatedWildcardType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType)

Example 23 with AnnotatedExecutableType

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

the class AnnotatedTypeFactory method getFnInterfaceFromTree.

/**
 * Returns the functional interface and the function type that this lambda or member references
 * targets.
 *
 * <p>The function type is the type of the single method declared in the functional interface
 * adapted as if it were invoked using the functional interface as the receiver expression.
 *
 * <p>The target type of a lambda or a method reference is the type to which it is assigned or
 * casted.
 *
 * @param tree lambda expression tree or member reference tree
 * @return the functional interface and the function type that this method reference or lambda
 *     targets.
 */
private Pair<AnnotatedDeclaredType, AnnotatedExecutableType> getFnInterfaceFromTree(Tree tree) {
    // Functional interface
    AnnotatedDeclaredType functionalInterfaceType = getFunctionalInterfaceType(tree);
    makeGroundTargetType(functionalInterfaceType, (DeclaredType) TreeUtils.typeOf(tree));
    // Functional method
    Element fnElement = TreeUtils.findFunction(tree, processingEnv);
    // Function type
    AnnotatedExecutableType functionType = (AnnotatedExecutableType) AnnotatedTypes.asMemberOf(types, this, functionalInterfaceType, fnElement);
    return Pair.of(functionalInterfaceType, functionType);
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) TypeParameterElement(javax.lang.model.element.TypeParameterElement)

Example 24 with AnnotatedExecutableType

use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType 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 25 with AnnotatedExecutableType

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

the class GenericAnnotatedTypeFactory method methodFromUse.

@Override
public Pair<AnnotatedExecutableType, List<AnnotatedTypeMirror>> methodFromUse(MethodInvocationTree tree) {
    Pair<AnnotatedExecutableType, List<AnnotatedTypeMirror>> mfuPair = super.methodFromUse(tree);
    AnnotatedExecutableType method = mfuPair.first;
    if (dependentTypesHelper != null) {
        dependentTypesHelper.viewpointAdaptMethod(tree, method);
    }
    poly.annotate(tree, method);
    return mfuPair;
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) ArrayList(java.util.ArrayList) List(java.util.List)

Aggregations

AnnotatedExecutableType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType)42 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)19 ExecutableElement (javax.lang.model.element.ExecutableElement)17 ArrayList (java.util.ArrayList)15 AnnotatedDeclaredType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType)15 ExpressionTree (com.sun.source.tree.ExpressionTree)13 MethodTree (com.sun.source.tree.MethodTree)13 List (java.util.List)13 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)12 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)12 Tree (com.sun.source.tree.Tree)12 VariableTree (com.sun.source.tree.VariableTree)12 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)9 AssignmentTree (com.sun.source.tree.AssignmentTree)7 ClassTree (com.sun.source.tree.ClassTree)7 NewArrayTree (com.sun.source.tree.NewArrayTree)7 ReturnTree (com.sun.source.tree.ReturnTree)7 NewClassTree (com.sun.source.tree.NewClassTree)6 VariableElement (javax.lang.model.element.VariableElement)6 AnnotationTree (com.sun.source.tree.AnnotationTree)5