use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType 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();
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType in project checker-framework by typetools.
the class TypeArgInferenceUtil method assignedTo.
/**
* Returns the annotated type that the leaf of path is assigned to, if it is within an
* assignment context. Returns the annotated type that the method invocation at the leaf is
* assigned to. If the result is a primitive, return the boxed version.
*
* @return type that path leaf is assigned to
*/
public static AnnotatedTypeMirror assignedTo(AnnotatedTypeFactory atypeFactory, TreePath path) {
Tree assignmentContext = TreeUtils.getAssignmentContext(path);
AnnotatedTypeMirror res;
if (assignmentContext == null) {
res = null;
} else if (assignmentContext instanceof AssignmentTree) {
ExpressionTree variable = ((AssignmentTree) assignmentContext).getVariable();
res = atypeFactory.getAnnotatedType(variable);
} else if (assignmentContext instanceof CompoundAssignmentTree) {
ExpressionTree variable = ((CompoundAssignmentTree) assignmentContext).getVariable();
res = atypeFactory.getAnnotatedType(variable);
} else if (assignmentContext instanceof MethodInvocationTree) {
MethodInvocationTree methodInvocation = (MethodInvocationTree) assignmentContext;
// TODO move to getAssignmentContext
if (methodInvocation.getMethodSelect() instanceof MemberSelectTree && ((MemberSelectTree) methodInvocation.getMethodSelect()).getExpression() == path.getLeaf()) {
return null;
}
ExecutableElement methodElt = TreeUtils.elementFromUse(methodInvocation);
AnnotatedTypeMirror receiver = atypeFactory.getReceiverType(methodInvocation);
res = assignedToExecutable(atypeFactory, path, methodElt, receiver, methodInvocation.getArguments());
} else if (assignmentContext instanceof NewArrayTree) {
// TODO: I left the previous implementation below, it definitely caused infinite loops
// TODO: if you called it from places like the TreeAnnotator.
res = null;
// FIXME: This may cause infinite loop
// AnnotatedTypeMirror type =
// atypeFactory.getAnnotatedType((NewArrayTree)assignmentContext);
// type = AnnotatedTypes.innerMostType(type);
// return type;
} else if (assignmentContext instanceof NewClassTree) {
// This need to be basically like MethodTree
NewClassTree newClassTree = (NewClassTree) assignmentContext;
ExecutableElement constructorElt = TreeUtils.constructor(newClassTree);
AnnotatedTypeMirror receiver = atypeFactory.fromNewClass(newClassTree);
res = assignedToExecutable(atypeFactory, path, constructorElt, receiver, newClassTree.getArguments());
} else if (assignmentContext instanceof ReturnTree) {
HashSet<Kind> kinds = new HashSet<>(Arrays.asList(Kind.LAMBDA_EXPRESSION, Kind.METHOD));
Tree enclosing = TreeUtils.enclosingOfKind(path, kinds);
if (enclosing.getKind() == Kind.METHOD) {
res = (atypeFactory.getAnnotatedType((MethodTree) enclosing)).getReturnType();
} else {
Pair<AnnotatedDeclaredType, AnnotatedExecutableType> fninf = atypeFactory.getFnInterfaceFromTree((LambdaExpressionTree) enclosing);
res = fninf.second.getReturnType();
}
} else if (assignmentContext instanceof VariableTree) {
res = assignedToVariable(atypeFactory, assignmentContext);
} else {
ErrorReporter.errorAbort("AnnotatedTypes.assignedTo: shouldn't be here!");
res = null;
}
if (res != null && TypesUtils.isPrimitive(res.getUnderlyingType())) {
return atypeFactory.getBoxedType((AnnotatedPrimitiveType) res);
} else {
return res;
}
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType in project checker-framework by typetools.
the class AFReducingVisitor method visitDeclared_Declared.
// From the JLS Spec:
// If F has the form G<..., Yk-1,U, Yk+1, ...>, where U involves Tj
@Override
public Void visitDeclared_Declared(AnnotatedDeclaredType subtype, AnnotatedDeclaredType supertype, Set<AFConstraint> constraints) {
if (subtype.wasRaw() || supertype.wasRaw()) {
// The error will be caught in {@link DefaultTypeArgumentInference#infer} and
// inference will be aborted, but type-checking will continue.
ErrorReporter.errorAbort("Can't infer type arguments when raw types are involved.");
return null;
}
if (!TypesUtils.isErasedSubtype(subtype.getUnderlyingType(), supertype.getUnderlyingType(), typeFactory.getContext().getTypeUtils())) {
return null;
}
AnnotatedDeclaredType subAsSuper = DefaultTypeHierarchy.castedAsSuper(subtype, supertype);
final List<AnnotatedTypeMirror> subTypeArgs = subAsSuper.getTypeArguments();
final List<AnnotatedTypeMirror> superTypeArgs = supertype.getTypeArguments();
for (int i = 0; i < subTypeArgs.size(); i++) {
final AnnotatedTypeMirror subTypeArg = subTypeArgs.get(i);
final AnnotatedTypeMirror superTypeArg = superTypeArgs.get(i);
// Since we always have both bounds in the checker framework we always compare both
if (superTypeArg.getKind() == TypeKind.WILDCARD) {
final AnnotatedWildcardType superWc = (AnnotatedWildcardType) superTypeArg;
if (subTypeArg.getKind() == TypeKind.WILDCARD) {
final AnnotatedWildcardType subWc = (AnnotatedWildcardType) subTypeArg;
TypeArgInferenceUtil.checkForUninferredTypes(subWc);
addConstraint(subWc.getExtendsBound(), superWc.getExtendsBound(), constraints);
addInverseConstraint(superWc.getSuperBound(), subWc.getSuperBound(), constraints);
} else {
addConstraint(subTypeArg, superWc.getExtendsBound(), constraints);
addInverseConstraint(superWc.getSuperBound(), subTypeArg, constraints);
}
} else {
// if F has the form G<..., Yk-1, U, Yk+1, ...>, where U is a type expression that
// involves Tj
addEqualityConstraint(subTypeArg, superTypeArg, constraints);
}
}
return null;
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType in project checker-framework by typetools.
the class BaseTypeVisitor method typeCheckVectorCopyIntoArgument.
/**
* Type checks the method arguments of {@code Vector.copyInto()}.
*
* <p>The Checker Framework special-cases the method invocation, as its type safety cannot be
* expressed by Java's type system.
*
* <p>For a Vector {@code v} of type {@code Vector<E>}, the method invocation {@code
* v.copyInto(arr)} is type-safe iff {@code arr} is an array of type {@code T[]}, where {@code
* T} is a subtype of {@code E}.
*
* <p>In other words, this method checks that the type argument of the receiver method is a
* subtype of the component type of the passed array argument.
*
* @param node a method invocation of {@code Vector.copyInto()}
* @param params the types of the parameters of {@code Vectory.copyInto()}
*/
protected void typeCheckVectorCopyIntoArgument(MethodInvocationTree node, List<? extends AnnotatedTypeMirror> params) {
assert params.size() == 1 : "invalid no. of parameters " + params + " found for method invocation " + node;
assert node.getArguments().size() == 1 : "invalid no. of arguments in method invocation " + node;
AnnotatedTypeMirror passed = atypeFactory.getAnnotatedType(node.getArguments().get(0));
AnnotatedArrayType passedAsArray = (AnnotatedArrayType) passed;
AnnotatedTypeMirror receiver = atypeFactory.getReceiverType(node);
if (vectorType == null) {
vectorType = atypeFactory.fromElement(elements.getTypeElement("java.util.Vector"));
}
AnnotatedDeclaredType receiverAsVector = AnnotatedTypes.asSuper(atypeFactory, receiver, vectorType);
if (receiverAsVector.getTypeArguments().isEmpty()) {
return;
}
AnnotatedTypeMirror argComponent = passedAsArray.getComponentType();
AnnotatedTypeMirror vectorTypeArg = receiverAsVector.getTypeArguments().get(0);
Tree errorLocation = node.getArguments().get(0);
if (TypesUtils.isErasedSubtype(vectorTypeArg.getUnderlyingType(), argComponent.getUnderlyingType(), types)) {
commonAssignmentCheck(argComponent, vectorTypeArg, errorLocation, "vector.copyinto.type.incompatible");
} else {
checker.report(Result.failure("vector.copyinto.type.incompatible", vectorTypeArg, argComponent), errorLocation);
}
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType in project checker-framework by typetools.
the class BaseTypeVisitor method isTypeCastSafe.
private boolean isTypeCastSafe(AnnotatedTypeMirror castType, AnnotatedTypeMirror exprType) {
QualifierHierarchy qualifierHierarchy = atypeFactory.getQualifierHierarchy();
if (castType.getKind() == TypeKind.DECLARED) {
// eliminate false positives, where the annotations are
// implicitly added by the declared type declaration
AnnotatedDeclaredType castDeclared = (AnnotatedDeclaredType) castType;
AnnotatedDeclaredType elementType = atypeFactory.fromElement((TypeElement) castDeclared.getUnderlyingType().asElement());
if (AnnotationUtils.areSame(castDeclared.getAnnotations(), elementType.getAnnotations())) {
return true;
}
}
if (checker.hasOption("checkCastElementType")) {
AnnotatedTypeMirror newCastType;
if (castType.getKind() == TypeKind.TYPEVAR) {
newCastType = ((AnnotatedTypeVariable) castType).getUpperBound();
} else {
newCastType = castType;
}
AnnotatedTypeMirror newExprType;
if (exprType.getKind() == TypeKind.TYPEVAR) {
newExprType = ((AnnotatedTypeVariable) exprType).getUpperBound();
} else {
newExprType = exprType;
}
if (!atypeFactory.getTypeHierarchy().isSubtype(newExprType, newCastType)) {
return false;
}
if (newCastType.getKind() == TypeKind.ARRAY && newExprType.getKind() != TypeKind.ARRAY) {
// doesn't, as in "(Object[]) o" where o is of type Object
return false;
} else if (newCastType.getKind() == TypeKind.DECLARED && newExprType.getKind() == TypeKind.DECLARED) {
int castSize = ((AnnotatedDeclaredType) newCastType).getTypeArguments().size();
int exprSize = ((AnnotatedDeclaredType) newExprType).getTypeArguments().size();
if (castSize != exprSize) {
// TODO: the same number of arguments actually doesn't guarantee anything.
return false;
}
} else if (castType.getKind() == TypeKind.TYPEVAR && exprType.getKind() == TypeKind.TYPEVAR) {
// If both the cast type and the casted expression are type variables, then check
// the bounds.
Set<AnnotationMirror> lowerBoundAnnotationsCast = AnnotatedTypes.findEffectiveLowerBoundAnnotations(qualifierHierarchy, castType);
Set<AnnotationMirror> lowerBoundAnnotationsExpr = AnnotatedTypes.findEffectiveLowerBoundAnnotations(qualifierHierarchy, exprType);
return qualifierHierarchy.isSubtype(lowerBoundAnnotationsExpr, lowerBoundAnnotationsCast) && qualifierHierarchy.isSubtype(exprType.getEffectiveAnnotations(), castType.getEffectiveAnnotations());
}
Set<AnnotationMirror> castAnnos;
if (castType.getKind() == TypeKind.TYPEVAR) {
// If the cast type is a type var, but the expression is not, then check that the
// type of the expression is a subtype of the lower bound.
castAnnos = AnnotatedTypes.findEffectiveLowerBoundAnnotations(qualifierHierarchy, castType);
} else {
castAnnos = castType.getAnnotations();
}
return qualifierHierarchy.isSubtype(exprType.getEffectiveAnnotations(), castAnnos);
} else {
// checkCastElementType option wasn't specified, so only check effective annotations,
return qualifierHierarchy.isSubtype(exprType.getEffectiveAnnotations(), castType.getEffectiveAnnotations());
}
}
Aggregations