use of org.checkerframework.framework.source.DiagMessage in project checker-framework by typetools.
the class FieldInvariants method isSuperInvariant.
/**
* Returns null if {@code superInvar} is a super invariant, otherwise returns the error message.
*
* @param superInvar the value to check for being a super invariant
* @param factory the type factory
* @return null if {@code superInvar} is a super invariant, otherwise returns the error message
*/
public DiagMessage isSuperInvariant(FieldInvariants superInvar, AnnotatedTypeFactory factory) {
QualifierHierarchy qualifierHierarchy = factory.getQualifierHierarchy();
if (!this.fields.containsAll(superInvar.fields)) {
List<String> missingFields = new ArrayList<>(superInvar.fields);
missingFields.removeAll(fields);
return new DiagMessage(Kind.ERROR, "field.invariant.not.found.superclass", String.join(", ", missingFields));
}
for (String field : superInvar.fields) {
List<AnnotationMirror> superQualifiers = superInvar.getQualifiersFor(field);
List<AnnotationMirror> subQualifiers = this.getQualifiersFor(field);
for (AnnotationMirror superA : superQualifiers) {
AnnotationMirror sub = qualifierHierarchy.findAnnotationInSameHierarchy(subQualifiers, superA);
if (sub == null || !qualifierHierarchy.isSubtype(sub, superA)) {
return new DiagMessage(Kind.ERROR, "field.invariant.not.subtype.superclass", field, sub, superA);
}
}
}
return null;
}
use of org.checkerframework.framework.source.DiagMessage in project checker-framework by typetools.
the class BaseTypeVisitor method checkFieldInvariantDeclarations.
/**
* Check that the field invariant declaration annotations meet the following requirements:
*
* <ol>
* <!-- The item numbering is referred to in the body of the method.-->
* <li value="1">If the superclass of {@code classTree} has a field invariant, then the field
* invariant for {@code classTree} must include all the fields in the superclass invariant
* and those fields' annotations must be a subtype (or equal) to the annotations for those
* fields in the superclass.
* <li value="2">The fields in the invariant must be a.) final and b.) declared in a superclass
* of {@code classTree}.
* <li value="3">The qualifier for each field must be a subtype of the annotation on the
* declaration of that field.
* <li value="4">The field invariant has an equal number of fields and qualifiers, or it has one
* qualifier and at least one field.
* </ol>
*
* @param classTree class that might have a field invariant
* @checker_framework.manual #field-invariants Field invariants
*/
protected void checkFieldInvariantDeclarations(ClassTree classTree) {
TypeElement elt = TreeUtils.elementFromDeclaration(classTree);
FieldInvariants invariants = atypeFactory.getFieldInvariants(elt);
if (invariants == null) {
// No invariants to check
return;
}
// Where to issue an error, if any.
Tree errorTree = atypeFactory.getFieldInvariantAnnotationTree(classTree.getModifiers().getAnnotations());
if (errorTree == null) {
// If the annotation was inherited, then there is no annotation tree, so issue the
// error on the class.
errorTree = classTree;
}
// Checks #4 (see method Javadoc)
if (!invariants.isWellFormed()) {
checker.reportError(errorTree, "field.invariant.not.wellformed");
return;
}
TypeMirror superClass = elt.getSuperclass();
List<String> fieldsNotFound = new ArrayList<>(invariants.getFields());
Set<VariableElement> fieldElts = ElementUtils.findFieldsInTypeOrSuperType(superClass, fieldsNotFound);
// Checks that fields are declared in super class. (#2b)
if (!fieldsNotFound.isEmpty()) {
String notFoundString = String.join(", ", fieldsNotFound);
checker.reportError(errorTree, "field.invariant.not.found", notFoundString);
}
FieldInvariants superInvar = atypeFactory.getFieldInvariants(TypesUtils.getTypeElement(superClass));
if (superInvar != null) {
// Checks #3 (see method Javadoc)
DiagMessage superError = invariants.isSuperInvariant(superInvar, atypeFactory);
if (superError != null) {
checker.report(errorTree, superError);
}
}
List<String> notFinal = new ArrayList<>();
for (VariableElement field : fieldElts) {
String fieldName = field.getSimpleName().toString();
if (!ElementUtils.isFinal(field)) {
notFinal.add(fieldName);
}
AnnotatedTypeMirror type = atypeFactory.getAnnotatedType(field);
List<AnnotationMirror> annos = invariants.getQualifiersFor(field.getSimpleName());
for (AnnotationMirror invariantAnno : annos) {
AnnotationMirror declaredAnno = type.getEffectiveAnnotationInHierarchy(invariantAnno);
if (declaredAnno == null) {
// invariant anno isn't in this hierarchy
continue;
}
if (!atypeFactory.getQualifierHierarchy().isSubtype(invariantAnno, declaredAnno)) {
// Checks #3
checker.reportError(errorTree, "field.invariant.not.subtype", fieldName, invariantAnno, declaredAnno);
}
}
}
// Checks #2a
if (!notFinal.isEmpty()) {
String notFinalString = String.join(", ", notFinal);
checker.reportError(errorTree, "field.invariant.not.final", notFinalString);
}
}
use of org.checkerframework.framework.source.DiagMessage 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);
}
}
}
}
use of org.checkerframework.framework.source.DiagMessage in project checker-framework by typetools.
the class BaseTypeValidator method isValid.
/**
* Validate the type against the given tree. This method both issues error messages and also
* returns a boolean value.
*
* <p>This is the entry point to the type validator. Neither this method nor visit should be
* called directly by a visitor, only use {@link BaseTypeVisitor#validateTypeOf(Tree)}.
*
* <p>This method is only called on top-level types, but it validates the entire type including
* components of a compound type. Subclasses should override this only if there is special-case
* behavior that should be performed only on top-level types.
*
* @param type the type to validate
* @param tree the tree from which the type originated. If the tree is a method tree, {@code type}
* is its return type. If the tree is a variable tree, {@code type} is the variable's type.
* @return true if the type is valid
*/
@Override
public boolean isValid(AnnotatedTypeMirror type, Tree tree) {
List<DiagMessage> diagMessages = isValidStructurally(atypeFactory.getQualifierHierarchy(), type);
if (!diagMessages.isEmpty()) {
for (DiagMessage d : diagMessages) {
checker.report(tree, d);
}
return false;
}
this.isValid = true;
this.checkTopLevelDeclaredOrPrimitiveType = shouldCheckTopLevelDeclaredOrPrimitiveType(type, tree);
visit(type, tree);
return this.isValid;
}
use of org.checkerframework.framework.source.DiagMessage in project checker-framework by typetools.
the class CalledMethodsVisitor method visitMethod.
@Override
public Void visitMethod(MethodTree node, Void p) {
ExecutableElement elt = TreeUtils.elementFromDeclaration(node);
AnnotationMirror ecmva = atypeFactory.getDeclAnnotation(elt, EnsuresCalledMethodsVarArgs.class);
if (ecmva != null) {
if (!elt.isVarArgs()) {
checker.report(node, new DiagMessage(Diagnostic.Kind.ERROR, "ensuresvarargs.invalid"));
}
}
return super.visitMethod(node, p);
}
Aggregations