use of org.checkerframework.checker.mustcall.MustCallAnnotatedTypeFactory in project checker-framework by typetools.
the class MustCallConsistencyAnalyzer method checkEnclosingMethodIsCreatesMustCallFor.
/**
* Checks that the method that encloses an assignment is marked with @CreatesMustCallFor
* annotation whose target is the object whose field is being re-assigned.
*
* @param node an assignment node whose lhs is a non-final, owning field
* @param enclosingMethod the MethodTree in which the re-assignment takes place
*/
private void checkEnclosingMethodIsCreatesMustCallFor(AssignmentNode node, MethodTree enclosingMethod) {
Node lhs = node.getTarget();
if (!(lhs instanceof FieldAccessNode)) {
return;
}
String receiverString = receiverAsString((FieldAccessNode) lhs);
if ("this".equals(receiverString) && TreeUtils.isConstructor(enclosingMethod)) {
// be annotated.
return;
}
ExecutableElement enclosingMethodElt = TreeUtils.elementFromDeclaration(enclosingMethod);
MustCallAnnotatedTypeFactory mcAtf = typeFactory.getTypeFactoryOfSubchecker(MustCallChecker.class);
List<String> cmcfValues = ResourceLeakVisitor.getCreatesMustCallForValues(enclosingMethodElt, mcAtf, typeFactory);
if (cmcfValues.isEmpty()) {
checker.reportError(enclosingMethod, "missing.creates.mustcall.for", enclosingMethodElt.getSimpleName().toString(), receiverString, ((FieldAccessNode) lhs).getFieldName());
return;
}
List<String> checked = new ArrayList<>();
for (String targetStrWithoutAdaptation : cmcfValues) {
String targetStr;
try {
targetStr = StringToJavaExpression.atMethodBody(targetStrWithoutAdaptation, enclosingMethod, checker).toString();
} catch (JavaExpressionParseException e) {
targetStr = targetStrWithoutAdaptation;
}
if (targetStr.equals(receiverString)) {
// This @CreatesMustCallFor annotation matches.
return;
}
checked.add(targetStr);
}
checker.reportError(enclosingMethod, "incompatible.creates.mustcall.for", enclosingMethodElt.getSimpleName().toString(), receiverString, ((FieldAccessNode) lhs).getFieldName(), String.join(", ", checked));
}
use of org.checkerframework.checker.mustcall.MustCallAnnotatedTypeFactory in project checker-framework by typetools.
the class MustCallConsistencyAnalyzer method isMustCallClose.
/**
* Returns true if must-call type of node only contains close. This is a helper method for
* handling try-with-resources statements.
*
* @param node the node.
* @return true if must-call type of node only contains close.
*/
boolean isMustCallClose(Node node) {
MustCallAnnotatedTypeFactory mcAtf = typeFactory.getTypeFactoryOfSubchecker(MustCallChecker.class);
AnnotatedTypeMirror mustCallAnnotatedType = mcAtf.getAnnotatedType(node.getTree());
AnnotationMirror mustCallAnnotation = mustCallAnnotatedType.getAnnotation(MustCall.class);
return typeFactory.getMustCallValues(mcAtf.withoutClose(mustCallAnnotation)).isEmpty();
}
use of org.checkerframework.checker.mustcall.MustCallAnnotatedTypeFactory in project checker-framework by typetools.
the class MustCallConsistencyAnalyzer method isValidCreatesMustCallForExpression.
/**
* Checks the validity of the given expression from an invoked method's {@link
* org.checkerframework.checker.mustcall.qual.CreatesMustCallFor} annotation. Helper method for
* {@link #checkCreatesMustCallForInvocation(Set, MethodInvocationNode)}.
*
* <p>An expression is valid if one of the following conditions is true: 1) the expression is an
* owning pointer, 2) the expression already has a tracked Obligation (i.e. there is already a
* resource alias in some Obligation's resource alias set that refers to the expression), or 3)
* the method in which the invocation occurs also has an @CreatesMustCallFor annotation, with the
* same expression.
*
* @param obligations the currently-tracked Obligations; this value is side-effected if there is
* an Obligation in it which tracks {@code expression} as one of its resource aliases
* @param expression an element of a method's @CreatesMustCallFor annotation
* @param path the path to the invocation of the method from whose @CreateMustCallFor annotation
* {@code expression} came
* @return true iff the expression is valid, as defined above
*/
private boolean isValidCreatesMustCallForExpression(Set<Obligation> obligations, JavaExpression expression, TreePath path) {
if (expression instanceof FieldAccess) {
Element elt = ((FieldAccess) expression).getField();
if (!checker.hasOption(MustCallChecker.NO_LIGHTWEIGHT_OWNERSHIP) && typeFactory.getDeclAnnotation(elt, Owning.class) != null) {
// The expression is an Owning field. This satisfies case 1.
return true;
}
} else if (expression instanceof LocalVariable) {
Element elt = ((LocalVariable) expression).getElement();
if (!checker.hasOption(MustCallChecker.NO_LIGHTWEIGHT_OWNERSHIP) && typeFactory.getDeclAnnotation(elt, Owning.class) != null) {
// This satisfies case 1.
return true;
} else {
Obligation toRemove = null;
Obligation toAdd = null;
for (Obligation obligation : obligations) {
ResourceAlias alias = obligation.getResourceAlias(expression);
if (alias != null) {
// This satisfies case 2 above. Remove all its aliases, then return below.
if (toRemove != null) {
throw new TypeSystemError("tried to remove multiple sets containing a reset expression at once");
}
toRemove = obligation;
toAdd = new Obligation(ImmutableSet.of(alias));
}
}
if (toRemove != null) {
obligations.remove(toRemove);
obligations.add(toAdd);
// This satisfies case 2.
return true;
}
}
}
// TODO: Getting this every time is inefficient if a method has many @CreatesMustCallFor
// annotations, but that should be rare.
MethodTree enclosingMethodTree = TreePathUtil.enclosingMethod(path);
if (enclosingMethodTree == null) {
return false;
}
ExecutableElement enclosingMethodElt = TreeUtils.elementFromDeclaration(enclosingMethodTree);
MustCallAnnotatedTypeFactory mcAtf = typeFactory.getTypeFactoryOfSubchecker(MustCallChecker.class);
List<String> enclosingCmcfValues = ResourceLeakVisitor.getCreatesMustCallForValues(enclosingMethodElt, mcAtf, typeFactory);
if (enclosingCmcfValues.isEmpty()) {
return false;
}
for (String enclosingCmcfValue : enclosingCmcfValues) {
JavaExpression enclosingTarget;
try {
enclosingTarget = StringToJavaExpression.atMethodBody(enclosingCmcfValue, enclosingMethodTree, checker);
} catch (JavaExpressionParseException e) {
// Do not issue an error here, because it would be a duplicate.
// The error will be issued by the Transfer class of the checker,
// via the CreatesMustCallForElementSupplier interface.
enclosingTarget = null;
}
if (areSame(expression, enclosingTarget)) {
// This satisfies case 3.
return true;
}
}
return false;
}
use of org.checkerframework.checker.mustcall.MustCallAnnotatedTypeFactory in project checker-framework by typetools.
the class ResourceLeakAnnotatedTypeFactory method getMustCallValue.
/**
* Returns the {@link MustCall#value} element/argument of the @MustCall annotation on the class
* type of {@code element}.
*
* <p>Do not use this method to get the MustCall value of an {@link
* org.checkerframework.checker.resourceleak.MustCallConsistencyAnalyzer.Obligation}. Instead, use
* {@link
* org.checkerframework.checker.resourceleak.MustCallConsistencyAnalyzer.Obligation#getMustCallMethods(ResourceLeakAnnotatedTypeFactory,
* CFStore)}.
*
* @param element an element
* @return the strings in its must-call type
*/
/* package-private */
List<String> getMustCallValue(Element element) {
MustCallAnnotatedTypeFactory mustCallAnnotatedTypeFactory = getTypeFactoryOfSubchecker(MustCallChecker.class);
AnnotatedTypeMirror mustCallAnnotatedType = mustCallAnnotatedTypeFactory.getAnnotatedType(element);
AnnotationMirror mustCallAnnotation = mustCallAnnotatedType.getAnnotation(MustCall.class);
return getMustCallValues(mustCallAnnotation);
}
use of org.checkerframework.checker.mustcall.MustCallAnnotatedTypeFactory in project checker-framework by typetools.
the class ResourceLeakAnnotatedTypeFactory method getMustCallValue.
/**
* Returns the {@link MustCall#value} element/argument of the @MustCall annotation on the type of
* {@code tree}.
*
* <p>If possible, prefer {@link #getMustCallValue(Tree)}, which accounts for flow-sensitive
* refinement.
*
* @param tree a tree
* @return the strings in its must-call type
*/
/* package-private */
List<String> getMustCallValue(Tree tree) {
MustCallAnnotatedTypeFactory mustCallAnnotatedTypeFactory = getTypeFactoryOfSubchecker(MustCallChecker.class);
AnnotatedTypeMirror mustCallAnnotatedType = mustCallAnnotatedTypeFactory.getAnnotatedType(tree);
AnnotationMirror mustCallAnnotation = mustCallAnnotatedType.getAnnotation(MustCall.class);
return getMustCallValues(mustCallAnnotation);
}
Aggregations