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();
}
Aggregations