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