use of org.checkerframework.framework.type.AnnotatedTypeMirror in project checker-framework by typetools.
the class BaseTypeVisitor method checkThrownExpression.
/**
* Checks the type of the thrown expression.
*
* <p>By default, this method checks that the thrown expression is a subtype of top.
*
* <p>Issue error if the thrown expression is not a sub type of the annotation given by {@link
* #getThrowUpperBoundAnnotations()}, the same as {@link
* #getExceptionParameterLowerBoundAnnotations()} by default.
*
* <p>Subclasses may override this method to change the behavior of this check. Subclasses wishing
* to enforce that the thrown expression be a subtype of a type besides {@link
* #getExceptionParameterLowerBoundAnnotations}, should override {@link
* #getThrowUpperBoundAnnotations()}.
*
* @param node ThrowTree to check
*/
protected void checkThrownExpression(ThrowTree node) {
AnnotatedTypeMirror throwType = atypeFactory.getAnnotatedType(node.getExpression());
Set<? extends AnnotationMirror> required = getThrowUpperBoundAnnotations();
switch(throwType.getKind()) {
case NULL:
case DECLARED:
Set<AnnotationMirror> found = throwType.getAnnotations();
if (!atypeFactory.getQualifierHierarchy().isSubtype(found, required)) {
checker.reportError(node.getExpression(), "throw", found, required);
}
break;
case TYPEVAR:
case WILDCARD:
// TODO: this code might change after the type var changes.
Set<AnnotationMirror> foundEffective = throwType.getEffectiveAnnotations();
if (!atypeFactory.getQualifierHierarchy().isSubtype(foundEffective, required)) {
checker.reportError(node.getExpression(), "throw", foundEffective, required);
}
break;
case UNION:
AnnotatedUnionType unionType = (AnnotatedUnionType) throwType;
Set<AnnotationMirror> foundPrimary = unionType.getAnnotations();
if (!atypeFactory.getQualifierHierarchy().isSubtype(foundPrimary, required)) {
checker.reportError(node.getExpression(), "throw", foundPrimary, required);
}
for (AnnotatedTypeMirror altern : unionType.getAlternatives()) {
if (!atypeFactory.getQualifierHierarchy().isSubtype(altern.getAnnotations(), required)) {
checker.reportError(node.getExpression(), "throw", altern.getAnnotations(), required);
}
}
break;
default:
throw new BugInCF("Unexpected throw expression type: " + throwType.getKind());
}
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror in project checker-framework by typetools.
the class BaseTypeVisitor method commonAssignmentCheck.
/**
* Checks the validity of an assignment (or pseudo-assignment) from a value to a variable and
* emits an error message (through the compiler's messaging interface) if it is not valid.
*
* @param varType the annotated type for the lvalue (usually a variable)
* @param valueExp the AST node for the rvalue (the new value)
* @param errorKey the error message key to use if the check fails
* @param extraArgs arguments to the error message key, before "found" and "expected" types
*/
protected void commonAssignmentCheck(AnnotatedTypeMirror varType, ExpressionTree valueExp, @CompilerMessageKey String errorKey, Object... extraArgs) {
if (shouldSkipUses(valueExp)) {
return;
}
if (valueExp.getKind() == Tree.Kind.MEMBER_REFERENCE || valueExp.getKind() == Tree.Kind.LAMBDA_EXPRESSION) {
// and do not need to be checked again as arguments.
return;
}
if (varType.getKind() == TypeKind.ARRAY && valueExp instanceof NewArrayTree && ((NewArrayTree) valueExp).getType() == null) {
AnnotatedTypeMirror compType = ((AnnotatedArrayType) varType).getComponentType();
NewArrayTree arrayTree = (NewArrayTree) valueExp;
assert arrayTree.getInitializers() != null : "array initializers are not expected to be null in: " + valueExp;
checkArrayInitialization(compType, arrayTree.getInitializers());
}
if (!validateTypeOf(valueExp)) {
return;
}
AnnotatedTypeMirror valueType = atypeFactory.getAnnotatedType(valueExp);
assert valueType != null : "null type for expression: " + valueExp;
commonAssignmentCheck(varType, valueType, valueExp, errorKey, extraArgs);
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror in project checker-framework by typetools.
the class BaseTypeVisitor method checkMethodInvocability.
/**
* Tests whether the method can be invoked using the receiver of the 'node' method invocation, and
* issues a "method.invocation" if the invocation is invalid.
*
* <p>This implementation tests whether the receiver in the method invocation is a subtype of the
* method receiver type. This behavior can be specialized by overriding skipReceiverSubtypeCheck.
*
* @param method the type of the invoked method
* @param node the method invocation node
*/
protected void checkMethodInvocability(AnnotatedExecutableType method, MethodInvocationTree node) {
if (method.getReceiverType() == null) {
// Static methods don't have a receiver to check.
return;
}
if (method.getElement().getKind() == ElementKind.CONSTRUCTOR) {
// ((AnnotatedExecutableType)atypeFactory.getAnnotatedType(atypeFactory.getEnclosingMethod(node))).getReceiverType();
return;
}
AnnotatedTypeMirror methodReceiver = method.getReceiverType().getErased();
AnnotatedTypeMirror treeReceiver = methodReceiver.shallowCopy(false);
AnnotatedTypeMirror rcv = atypeFactory.getReceiverType(node);
treeReceiver.addAnnotations(rcv.getEffectiveAnnotations());
if (!skipReceiverSubtypeCheck(node, methodReceiver, rcv)) {
// The diagnostic can be a bit misleading because the check is of the receiver but `node` is
// the entire method invocation (where the receiver might be implicit).
commonAssignmentCheckStartDiagnostic(methodReceiver, treeReceiver, node);
boolean success = atypeFactory.getTypeHierarchy().isSubtype(treeReceiver, methodReceiver);
commonAssignmentCheckEndDiagnostic(success, null, methodReceiver, treeReceiver, node);
if (!success) {
reportMethodInvocabilityError(node, treeReceiver, methodReceiver);
}
}
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror in project checker-framework by typetools.
the class BaseTypeVisitor method visitReturn.
/**
* Checks that the type of the return expression is a subtype of the enclosing method required
* return type. If not, it issues a "return" error.
*/
@Override
public Void visitReturn(ReturnTree node, Void p) {
// Don't try to check return expressions for void methods.
if (node.getExpression() == null) {
return super.visitReturn(node, p);
}
Tree enclosing = TreePathUtil.enclosingOfKind(getCurrentPath(), new HashSet<>(Arrays.asList(Tree.Kind.METHOD, Tree.Kind.LAMBDA_EXPRESSION)));
AnnotatedTypeMirror ret = null;
if (enclosing.getKind() == Tree.Kind.METHOD) {
MethodTree enclosingMethod = TreePathUtil.enclosingMethod(getCurrentPath());
boolean valid = validateTypeOf(enclosing);
if (valid) {
ret = atypeFactory.getMethodReturnType(enclosingMethod, node);
}
} else {
AnnotatedExecutableType result = atypeFactory.getFunctionTypeFromTree((LambdaExpressionTree) enclosing);
ret = result.getReturnType();
}
if (ret != null) {
commonAssignmentCheck(ret, node.getExpression(), "return");
}
return super.visitReturn(node, p);
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror in project checker-framework by typetools.
the class BaseTypeVisitor method checkQualifierParameter.
/**
* Issues an error if {@code classTree} has polymorphic fields but is not annotated with
* {@code @HasQualifierParameter}. Always issue a warning if the type of a static field is
* annotated with a polymorphic qualifier.
*
* <p>Issues an error if {@code classTree} extends or implements a class/interface that has a
* qualifier parameter, but this class does not.
*
* @param classTree the ClassTree to check for polymorphic fields
*/
protected void checkQualifierParameter(ClassTree classTree) {
// Set of polymorphic qualifiers for hierarchies that do not have a qualifier parameter and
// therefor cannot appear on a field.
Set<AnnotationMirror> illegalOnFieldsPolyQual = AnnotationUtils.createAnnotationSet();
// Set of polymorphic annotations for all hierarchies
Set<AnnotationMirror> polys = AnnotationUtils.createAnnotationSet();
TypeElement classElement = TreeUtils.elementFromDeclaration(classTree);
for (AnnotationMirror top : atypeFactory.getQualifierHierarchy().getTopAnnotations()) {
AnnotationMirror poly = atypeFactory.getQualifierHierarchy().getPolymorphicAnnotation(top);
if (poly != null) {
polys.add(poly);
}
if (atypeFactory.hasExplicitQualifierParameterInHierarchy(classElement, top) && atypeFactory.hasExplicitNoQualifierParameterInHierarchy(classElement, top)) {
checker.reportError(classTree, "conflicting.qual.param", top);
}
if (atypeFactory.hasQualifierParameterInHierarchy(classElement, top)) {
continue;
}
if (poly != null) {
illegalOnFieldsPolyQual.add(poly);
}
Element extendsEle = TypesUtils.getTypeElement(classElement.getSuperclass());
if (extendsEle != null && atypeFactory.hasQualifierParameterInHierarchy(extendsEle, top)) {
checker.reportError(classTree, "missing.has.qual.param", top);
} else {
for (TypeMirror interfaceType : classElement.getInterfaces()) {
Element interfaceEle = TypesUtils.getTypeElement(interfaceType);
if (atypeFactory.hasQualifierParameterInHierarchy(interfaceEle, top)) {
checker.reportError(classTree, "missing.has.qual.param", top);
// only issue error once
break;
}
}
}
}
for (Tree mem : classTree.getMembers()) {
if (mem.getKind() == Tree.Kind.VARIABLE) {
AnnotatedTypeMirror fieldType = atypeFactory.getAnnotatedType(mem);
List<DiagMessage> hasIllegalPoly;
if (ElementUtils.isStatic(TreeUtils.elementFromDeclaration((VariableTree) mem))) {
// A polymorphic qualifier is not allowed on a static field even if the class
// has a qualifier parameter.
hasIllegalPoly = polyScanner.visit(fieldType, polys);
} else {
hasIllegalPoly = polyScanner.visit(fieldType, illegalOnFieldsPolyQual);
}
for (DiagMessage dm : hasIllegalPoly) {
checker.report(mem, dm);
}
}
}
}
Aggregations