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