Search in sources :

Example 1 with JCMemberReference

use of com.sun.tools.javac.tree.JCTree.JCMemberReference in project checker-framework by typetools.

the class BaseTypeVisitor method checkMethodReferenceAsOverride.

/**
 * Check that a method reference is allowed. Using the OverrideChecker class.
 *
 * @param memberReferenceTree the tree for the method reference
 * @return true if the method reference is allowed
 */
protected boolean checkMethodReferenceAsOverride(MemberReferenceTree memberReferenceTree, Void p) {
    Pair<AnnotatedDeclaredType, AnnotatedExecutableType> result = atypeFactory.getFnInterfaceFromTree(memberReferenceTree);
    // The type to which the member reference is assigned -- also known as the target type of the reference.
    AnnotatedDeclaredType functionalInterface = result.first;
    // The type of the single method that is declared by the functional interface.
    AnnotatedExecutableType functionType = result.second;
    // ========= Overriding Type =========
    // This doesn't get the correct type for a "MyOuter.super" based on the receiver of the
    // enclosing method.
    // That is handled separately in method receiver check.
    // The type of the expression or type use, <expression>::method or <type use>::method.
    final ExpressionTree qualifierExpression = memberReferenceTree.getQualifierExpression();
    final ReferenceKind memRefKind = ((JCMemberReference) memberReferenceTree).kind;
    AnnotatedTypeMirror enclosingType;
    if (memberReferenceTree.getMode() == ReferenceMode.NEW || memRefKind == ReferenceKind.UNBOUND || memRefKind == ReferenceKind.STATIC) {
        // The "qualifier expression" is a type tree.
        enclosingType = atypeFactory.getAnnotatedTypeFromTypeTree(qualifierExpression);
    } else {
        // The "qualifier expression" is an expression.
        enclosingType = atypeFactory.getAnnotatedType(qualifierExpression);
    }
    // ========= Overriding Executable =========
    // The ::method element, see JLS 15.13.1 Compile-Time Declaration of a Method Reference
    ExecutableElement compileTimeDeclaration = (ExecutableElement) TreeUtils.elementFromTree(memberReferenceTree);
    if (enclosingType.getKind() == TypeKind.DECLARED && ((AnnotatedDeclaredType) enclosingType).wasRaw()) {
        if (memRefKind == ReferenceKind.UNBOUND) {
            // The method reference is of the form: Type # instMethod
            // and Type is a raw type.
            // If the first parameter of the function type, p1, is a subtype
            // of type, then type should be p1.  This has the effect of "inferring" the
            // class type parameter.
            AnnotatedTypeMirror p1 = functionType.getParameterTypes().get(0);
            TypeMirror asSuper = TypesUtils.asSuper(p1.getUnderlyingType(), enclosingType.getUnderlyingType(), atypeFactory.getProcessingEnv());
            if (asSuper != null) {
                enclosingType = AnnotatedTypes.asSuper(atypeFactory, p1, enclosingType);
            }
        }
    // else method reference is something like ArrayList::new
    // TODO: Use diamond, <>, inference to infer the class type arguments.
    // for now this case is skipped below in checkMethodReferenceInference.
    }
    // The type of the compileTimeDeclaration if it were invoked with a receiver expression
    // of type {@code type}
    AnnotatedExecutableType invocationType = atypeFactory.methodFromUse(memberReferenceTree, compileTimeDeclaration, enclosingType).first;
    if (checkMethodReferenceInference(memberReferenceTree, invocationType, enclosingType)) {
        // #checkMethodReferenceInference issued a warning.
        return true;
    }
    // functionType.getReturnType()
    if (invocationType.getTypeVariables().isEmpty() && !functionType.getTypeVariables().isEmpty()) {
        functionType = functionType.getErased();
    }
    // Use the function type's parameters to resolve polymorphic qualifiers.
    QualifierPolymorphism poly = new QualifierPolymorphism(atypeFactory.getProcessingEnv(), atypeFactory);
    poly.annotate(functionType, invocationType);
    AnnotatedTypeMirror invocationReturnType;
    if (compileTimeDeclaration.getKind() == ElementKind.CONSTRUCTOR) {
        if (enclosingType.getKind() == TypeKind.ARRAY) {
            // Special casing for the return of array constructor
            invocationReturnType = enclosingType;
        } else {
            invocationReturnType = atypeFactory.getResultingTypeOfConstructorMemberReference(memberReferenceTree, invocationType);
        }
    } else {
        invocationReturnType = invocationType.getReturnType();
    }
    AnnotatedTypeMirror functionTypeReturnType = functionType.getReturnType();
    if (functionTypeReturnType.getKind() == TypeKind.VOID) {
        // If the functional interface return type is void, the overriding return
        // type doesn't matter.
        functionTypeReturnType = invocationReturnType;
    }
    // Check the member reference as if invocationType overrides functionType.
    OverrideChecker overrideChecker = createOverrideChecker(memberReferenceTree, invocationType, enclosingType, invocationReturnType, functionType, functionalInterface, functionTypeReturnType);
    return overrideChecker.checkOverride();
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) QualifierPolymorphism(org.checkerframework.framework.util.QualifierPolymorphism) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) TypeMirror(javax.lang.model.type.TypeMirror) JCMemberReference(com.sun.tools.javac.tree.JCTree.JCMemberReference) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) ExecutableElement(javax.lang.model.element.ExecutableElement) ReferenceKind(com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Aggregations

ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)1 ExpressionTree (com.sun.source.tree.ExpressionTree)1 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)1 JCMemberReference (com.sun.tools.javac.tree.JCTree.JCMemberReference)1 ReferenceKind (com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind)1 ExecutableElement (javax.lang.model.element.ExecutableElement)1 TypeMirror (javax.lang.model.type.TypeMirror)1 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)1 AnnotatedDeclaredType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType)1 AnnotatedExecutableType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType)1 QualifierPolymorphism (org.checkerframework.framework.util.QualifierPolymorphism)1