use of org.checkerframework.javacutil.TypeSystemError in project checker-framework by typetools.
the class MustCallConsistencyAnalyzer method checkReassignmentToField.
/**
* Issues an error if the given re-assignment to a non-final, owning field is not valid. A
* re-assignment is valid if the called methods type of the lhs before the assignment satisfies
* the must-call obligations of the field.
*
* @param obligations current tracked Obligations
* @param node an assignment to a non-final, owning field
*/
private void checkReassignmentToField(Set<Obligation> obligations, AssignmentNode node) {
Node lhsNode = node.getTarget();
if (!(lhsNode instanceof FieldAccessNode)) {
throw new TypeSystemError("checkReassignmentToField: non-field node " + node + " of class " + node.getClass());
}
FieldAccessNode lhs = (FieldAccessNode) lhsNode;
Node receiver = lhs.getReceiver();
// TODO: it would be better to defer getting the path until after checking
// for a CreatesMustCallFor annotation, because getting the path can be expensive.
// It might be possible to exploit the CFG structure to find the containing
// method (rather than using the path, as below), because if a method is being
// analyzed then it should be the root of the CFG (I think).
TreePath currentPath = typeFactory.getPath(node.getTree());
MethodTree enclosingMethodTree = TreePathUtil.enclosingMethod(currentPath);
if (enclosingMethodTree == null) {
// also a declaration must be a field initializer.
if (node.getTree().getKind() == Tree.Kind.VARIABLE) {
return;
} else {
// Issue an error if the field has a non-empty must-call type.
MustCallAnnotatedTypeFactory mcTypeFactory = typeFactory.getTypeFactoryOfSubchecker(MustCallChecker.class);
AnnotationMirror mcAnno = mcTypeFactory.getAnnotatedType(lhs.getElement()).getAnnotation(MustCall.class);
List<String> mcValues = AnnotationUtils.getElementValueArray(mcAnno, mcTypeFactory.getMustCallValueElement(), String.class);
if (mcValues.isEmpty()) {
return;
}
Element lhsElement = TreeUtils.elementFromTree(lhs.getTree());
checker.reportError(node.getTree(), "required.method.not.called", formatMissingMustCallMethods(mcValues), "field " + lhsElement.getSimpleName().toString(), lhsElement.asType().toString(), "Field assignment outside method or declaration might overwrite field's current value");
return;
}
}
// on the method declaration), or 2) the rhs is a null literal (so there's nothing to reset).
if (!(receiver instanceof LocalVariableNode && varTrackedInObligations(obligations, (LocalVariableNode) receiver)) && !(node.getExpression() instanceof NullLiteralNode)) {
checkEnclosingMethodIsCreatesMustCallFor(node, enclosingMethodTree);
}
MustCallAnnotatedTypeFactory mcTypeFactory = typeFactory.getTypeFactoryOfSubchecker(MustCallChecker.class);
// Get the Must Call type for the field. If there's info about this field in the store, use
// that. Otherwise, use the declared type of the field
CFStore mcStore = mcTypeFactory.getStoreBefore(lhs);
CFValue mcValue = mcStore.getValue(lhs);
AnnotationMirror mcAnno;
if (mcValue == null) {
// No store value, so use the declared type.
mcAnno = mcTypeFactory.getAnnotatedType(lhs.getElement()).getAnnotation(MustCall.class);
} else {
mcAnno = AnnotationUtils.getAnnotationByClass(mcValue.getAnnotations(), MustCall.class);
}
List<String> mcValues = AnnotationUtils.getElementValueArray(mcAnno, mcTypeFactory.getMustCallValueElement(), String.class);
if (mcValues.isEmpty()) {
return;
}
// Get the store before the RHS rather than the assignment node, because the CFG always has
// the RHS first. If the RHS has side-effects, then the assignment node's store will have
// had its inferred types erased.
Node rhs = node.getExpression();
CFStore cmStoreBefore = typeFactory.getStoreBefore(rhs);
CFValue cmValue = cmStoreBefore == null ? null : cmStoreBefore.getValue(lhs);
AnnotationMirror cmAnno = null;
if (cmValue != null) {
for (AnnotationMirror anno : cmValue.getAnnotations()) {
if (AnnotationUtils.areSameByName(anno, "org.checkerframework.checker.calledmethods.qual.CalledMethods")) {
cmAnno = anno;
break;
}
}
}
if (cmAnno == null) {
cmAnno = typeFactory.top;
}
if (!calledMethodsSatisfyMustCall(mcValues, cmAnno)) {
Element lhsElement = TreeUtils.elementFromTree(lhs.getTree());
if (!checker.shouldSkipUses(lhsElement)) {
checker.reportError(node.getTree(), "required.method.not.called", formatMissingMustCallMethods(mcValues), "field " + lhsElement.getSimpleName().toString(), lhsElement.asType().toString(), " Non-final owning field might be overwritten");
}
}
}
use of org.checkerframework.javacutil.TypeSystemError in project checker-framework by typetools.
the class MustCallAnnotatedTypeFactory method methodFromUsePreSubstitution.
/**
* Treat non-owning method parameters as @MustCallUnknown (top) when the method is called.
*/
@Override
public void methodFromUsePreSubstitution(ExpressionTree tree, AnnotatedExecutableType type) {
ExecutableElement declaration;
if (tree instanceof MethodInvocationTree) {
declaration = TreeUtils.elementFromUse((MethodInvocationTree) tree);
} else if (tree instanceof MemberReferenceTree) {
declaration = (ExecutableElement) TreeUtils.elementFromTree(tree);
} else {
throw new TypeSystemError("unexpected type of method tree: " + tree.getKind());
}
changeNonOwningParameterTypesToTop(declaration, type);
super.methodFromUsePreSubstitution(tree, type);
}
use of org.checkerframework.javacutil.TypeSystemError in project checker-framework by typetools.
the class DefaultQualifierKindHierarchy method createDirectSuperMap.
/**
* Creates a mapping from a {@link QualifierKind} to a set of its direct super qualifier kinds.
* The direct super qualifier kinds do not contain the qualifier itself. This mapping is used to
* create the bottom set, to create the top set, and by {@link
* #initializeQualifierKindFields(Map)}.
*
* <p>This implementation uses the {@link SubtypeOf} meta-annotation. Subclasses may override this
* method to create the direct super map some other way.
*
* <p>Note that this method is called from the constructor when {@link #nameToQualifierKind} and
* {@link #qualifierKinds} are the only fields that have nonnull values. This method is not
* static, so it can be overridden by subclasses.
*
* @return a mapping from each {@link QualifierKind} to a set of its direct super qualifiers
*/
@RequiresNonNull({ "this.nameToQualifierKind", "this.qualifierKinds" })
protected Map<DefaultQualifierKind, Set<DefaultQualifierKind>> createDirectSuperMap(@UnderInitialization DefaultQualifierKindHierarchy this, ) {
Map<DefaultQualifierKind, Set<DefaultQualifierKind>> directSuperMap = new TreeMap<>();
for (DefaultQualifierKind qualifierKind : qualifierKinds) {
SubtypeOf subtypeOfMetaAnno = qualifierKind.getAnnotationClass().getAnnotation(SubtypeOf.class);
if (subtypeOfMetaAnno == null) {
// qualifierKind has no @SubtypeOf: it must be top or polymorphic
continue;
}
Set<DefaultQualifierKind> directSupers = new TreeSet<>();
for (Class<? extends Annotation> superClazz : subtypeOfMetaAnno.value()) {
String superName = QualifierKindHierarchy.annotationClassName(superClazz);
DefaultQualifierKind superQualifier = nameToQualifierKind.get(superName);
if (superQualifier == null) {
throw new TypeSystemError("%s @Subtype argument %s isn't in the hierarchy. Qualifiers: [%s]", qualifierKind, superName, StringsPlume.join(", ", qualifierKinds));
}
directSupers.add(superQualifier);
}
directSuperMap.put(qualifierKind, directSupers);
}
return directSuperMap;
}
use of org.checkerframework.javacutil.TypeSystemError in project checker-framework by typetools.
the class ValueQualifierHierarchy method leastUpperBound.
/**
* Determines the least upper bound of a1 and a2, which contains the union of their sets of
* possible values.
*
* @return the least upper bound of a1 and a2
*/
@Override
public AnnotationMirror leastUpperBound(AnnotationMirror a1, AnnotationMirror a2) {
if (!AnnotationUtils.areSameByName(getTopAnnotation(a1), getTopAnnotation(a2))) {
// The annotations are in different hierarchies
return null;
}
a1 = atypeFactory.convertSpecialIntRangeToStandardIntRange(a1);
a2 = atypeFactory.convertSpecialIntRangeToStandardIntRange(a2);
if (isSubtype(a1, a2)) {
return a2;
} else if (isSubtype(a2, a1)) {
return a1;
}
String qual1 = AnnotationUtils.annotationName(a1);
String qual2 = AnnotationUtils.annotationName(a2);
if (qual1.equals(qual2)) {
// If both are the same type, determine the type and merge
switch(qual1) {
case ValueAnnotatedTypeFactory.INTRANGE_NAME:
// special handling for IntRange
Range intrange1 = atypeFactory.getRange(a1);
Range intrange2 = atypeFactory.getRange(a2);
return atypeFactory.createIntRangeAnnotation(intrange1.union(intrange2));
case ValueAnnotatedTypeFactory.ARRAYLENRANGE_NAME:
// special handling for ArrayLenRange
Range range1 = atypeFactory.getRange(a1);
Range range2 = atypeFactory.getRange(a2);
return atypeFactory.createArrayLenRangeAnnotation(range1.union(range2));
case ValueAnnotatedTypeFactory.INTVAL_NAME:
List<Long> longs = atypeFactory.getIntValues(a1);
SystemUtil.addWithoutDuplicates(longs, atypeFactory.getIntValues(a2));
return atypeFactory.createIntValAnnotation(longs);
case ValueAnnotatedTypeFactory.ARRAYLEN_NAME:
List<Integer> arrayLens = atypeFactory.getArrayLength(a1);
SystemUtil.addWithoutDuplicates(arrayLens, atypeFactory.getArrayLength(a2));
return atypeFactory.createArrayLenAnnotation(arrayLens);
case ValueAnnotatedTypeFactory.STRINGVAL_NAME:
List<String> strings = atypeFactory.getStringValues(a1);
SystemUtil.addWithoutDuplicates(strings, atypeFactory.getStringValues(a2));
return atypeFactory.createStringAnnotation(strings);
case ValueAnnotatedTypeFactory.BOOLVAL_NAME:
List<Boolean> bools = atypeFactory.getBooleanValues(a1);
SystemUtil.addWithoutDuplicates(bools, atypeFactory.getBooleanValues(a2));
return atypeFactory.createBooleanAnnotation(bools);
case ValueAnnotatedTypeFactory.DOUBLEVAL_NAME:
List<Double> doubles = atypeFactory.getDoubleValues(a1);
SystemUtil.addWithoutDuplicates(doubles, atypeFactory.getDoubleValues(a2));
return atypeFactory.createDoubleAnnotation(doubles);
case ValueAnnotatedTypeFactory.MATCHES_REGEX_NAME:
List<@Regex String> regexes = atypeFactory.getMatchesRegexValues(a1);
SystemUtil.addWithoutDuplicates(regexes, atypeFactory.getMatchesRegexValues(a2));
return atypeFactory.createMatchesRegexAnnotation(regexes);
default:
throw new TypeSystemError("default case: %s %s %s%n", qual1, a1, a2);
}
}
// Special handling for dealing with the lub of two annotations that are distinct but
// convertible (e.g. a StringVal and a MatchesRegex, or an IntVal and an IntRange).
// Each of these variables is an annotation of the given type, or is null if neither of
// the arguments to leastUpperBound is of the given types.
AnnotationMirror arrayLenAnno = null;
AnnotationMirror arrayLenRangeAnno = null;
AnnotationMirror stringValAnno = null;
AnnotationMirror matchesRegexAnno = null;
AnnotationMirror intValAnno = null;
AnnotationMirror intRangeAnno = null;
AnnotationMirror doubleValAnno = null;
switch(qual1) {
case ValueAnnotatedTypeFactory.ARRAYLEN_NAME:
arrayLenAnno = a1;
break;
case ValueAnnotatedTypeFactory.ARRAYLENRANGE_NAME:
arrayLenRangeAnno = a1;
break;
case ValueAnnotatedTypeFactory.STRINGVAL_NAME:
stringValAnno = a1;
break;
case ValueAnnotatedTypeFactory.MATCHES_REGEX_NAME:
matchesRegexAnno = a1;
break;
case ValueAnnotatedTypeFactory.INTVAL_NAME:
intValAnno = a1;
break;
case ValueAnnotatedTypeFactory.INTRANGE_NAME:
intRangeAnno = a1;
break;
case ValueAnnotatedTypeFactory.DOUBLEVAL_NAME:
doubleValAnno = a1;
break;
default:
}
switch(qual2) {
case ValueAnnotatedTypeFactory.ARRAYLEN_NAME:
arrayLenAnno = a2;
break;
case ValueAnnotatedTypeFactory.ARRAYLENRANGE_NAME:
arrayLenRangeAnno = a2;
break;
case ValueAnnotatedTypeFactory.STRINGVAL_NAME:
stringValAnno = a2;
break;
case ValueAnnotatedTypeFactory.MATCHES_REGEX_NAME:
matchesRegexAnno = a2;
break;
case ValueAnnotatedTypeFactory.INTVAL_NAME:
intValAnno = a2;
break;
case ValueAnnotatedTypeFactory.INTRANGE_NAME:
intRangeAnno = a2;
break;
case ValueAnnotatedTypeFactory.DOUBLEVAL_NAME:
doubleValAnno = a2;
break;
default:
}
// a StringVal with one of them, or a StringVal and a MatchesRegex.
if (arrayLenAnno != null && arrayLenRangeAnno != null) {
return leastUpperBound(arrayLenRangeAnno, atypeFactory.convertArrayLenToArrayLenRange(arrayLenAnno));
} else if (stringValAnno != null && arrayLenAnno != null) {
return leastUpperBound(arrayLenAnno, atypeFactory.convertStringValToArrayLen(stringValAnno));
} else if (stringValAnno != null && arrayLenRangeAnno != null) {
return leastUpperBound(arrayLenRangeAnno, atypeFactory.convertStringValToArrayLenRange(stringValAnno));
} else if (stringValAnno != null && matchesRegexAnno != null) {
return leastUpperBound(matchesRegexAnno, atypeFactory.convertStringValToMatchesRegex(stringValAnno));
}
if (doubleValAnno != null) {
if (intRangeAnno != null) {
intValAnno = atypeFactory.convertIntRangeToIntVal(intRangeAnno);
if (AnnotationUtils.areSameByName(intValAnno, ValueAnnotatedTypeFactory.UNKNOWN_NAME)) {
intValAnno = null;
}
}
if (intValAnno != null) {
// Convert intValAnno to a @DoubleVal AnnotationMirror
AnnotationMirror doubleValAnno2 = atypeFactory.convertIntValToDoubleVal(intValAnno);
return leastUpperBound(doubleValAnno, doubleValAnno2);
}
return atypeFactory.UNKNOWNVAL;
}
if (intRangeAnno != null && intValAnno != null) {
// Convert intValAnno to an @IntRange AnnotationMirror
AnnotationMirror intRangeAnno2 = atypeFactory.convertIntValToIntRange(intValAnno);
return leastUpperBound(intRangeAnno, intRangeAnno2);
}
// In all other cases, the LUB is UnknownVal.
return atypeFactory.UNKNOWNVAL;
}
use of org.checkerframework.javacutil.TypeSystemError in project checker-framework by typetools.
the class ValueTreeAnnotator method visitEnumConstant.
/**
* Default the type of an enum constant {@code E.V} to {@code @StringVal("V")}. Does nothing if
* the argument is not an enum constant.
*
* @param tree an Identifier or MemberSelect tree that might be an enum
* @param type the type of that tree
*/
private void visitEnumConstant(ExpressionTree tree, AnnotatedTypeMirror type) {
Element decl = TreeUtils.elementFromTree(tree);
if (decl.getKind() != ElementKind.ENUM_CONSTANT) {
return;
}
Name id;
switch(tree.getKind()) {
case MEMBER_SELECT:
id = ((MemberSelectTree) tree).getIdentifier();
break;
case IDENTIFIER:
id = ((IdentifierTree) tree).getName();
break;
default:
throw new TypeSystemError("unexpected kind of enum constant use tree: " + tree.getKind());
}
AnnotationMirror stringVal = atypeFactory.createStringAnnotation(Collections.singletonList(id.toString()));
type.replaceAnnotation(stringVal);
}
Aggregations