use of org.checkerframework.dataflow.analysis.FlowExpressions.FieldAccess in project checker-framework by typetools.
the class InitializationTransfer method visitAssignment.
@Override
public TransferResult<V, S> visitAssignment(AssignmentNode n, TransferInput<V, S> in) {
TransferResult<V, S> result = super.visitAssignment(n, in);
assert result instanceof RegularTransferResult;
Receiver expr = FlowExpressions.internalReprOf(analysis.getTypeFactory(), n.getTarget());
// initialized.
if (!expr.containsUnknown()) {
if (expr instanceof FieldAccess) {
FieldAccess fa = (FieldAccess) expr;
result.getRegularStore().addInitializedField(fa);
}
}
return result;
}
use of org.checkerframework.dataflow.analysis.FlowExpressions.FieldAccess in project checker-framework by typetools.
the class InitializationVisitor method checkContract.
@Override
protected boolean checkContract(Receiver expr, AnnotationMirror necessaryAnnotation, AnnotationMirror inferredAnnotation, CFAbstractStore<?, ?> store) {
// also use the information about initialized fields to check contracts
final AnnotationMirror invariantAnno = atypeFactory.getFieldInvariantAnnotation();
if (atypeFactory.getQualifierHierarchy().isSubtype(invariantAnno, necessaryAnnotation)) {
if (expr instanceof FieldAccess) {
FieldAccess fa = (FieldAccess) expr;
if (fa.getReceiver() instanceof ThisReference || fa.getReceiver() instanceof ClassName) {
@SuppressWarnings("unchecked") Store s = (Store) store;
if (s.isFieldInitialized(fa.getField())) {
AnnotatedTypeMirror fieldType = atypeFactory.getAnnotatedType(fa.getField());
// is this an invariant-field?
if (AnnotationUtils.containsSame(fieldType.getAnnotations(), invariantAnno)) {
return true;
}
}
} else {
Set<AnnotationMirror> recvAnnoSet;
@SuppressWarnings("unchecked") Value value = (Value) store.getValue(fa.getReceiver());
if (value != null) {
recvAnnoSet = value.getAnnotations();
} else if (fa.getReceiver() instanceof LocalVariable) {
Element elem = ((LocalVariable) fa.getReceiver()).getElement();
AnnotatedTypeMirror recvType = atypeFactory.getAnnotatedType(elem);
recvAnnoSet = recvType.getAnnotations();
} else {
// Is there anything better we could do?
return false;
}
boolean isRecvCommitted = false;
for (AnnotationMirror anno : recvAnnoSet) {
if (atypeFactory.isCommitted(anno)) {
isRecvCommitted = true;
}
}
AnnotatedTypeMirror fieldType = atypeFactory.getAnnotatedType(fa.getField());
// has the invariant type.
if (isRecvCommitted && AnnotationUtils.containsSame(fieldType.getAnnotations(), invariantAnno)) {
return true;
}
}
}
}
return super.checkContract(expr, necessaryAnnotation, inferredAnnotation, store);
}
use of org.checkerframework.dataflow.analysis.FlowExpressions.FieldAccess in project checker-framework by typetools.
the class CFAbstractStore method removeConflicting.
/**
* Remove any information in the store that might not be true any more after {@code arrayAccess}
* has been assigned a new value (with the abstract value {@code val}). This includes the
* following steps (assume that {@code arrayAccess} is of the form <em>a[i]</em> for some
* <em>a</em>.
*
* <ol>
* <li value="1">Remove any abstract value for other array access <em>b[j]</em> where
* <em>a</em> and <em>b</em> can be aliases, or where either <em>b</em> or <em>j</em>
* contains a modifiable alias of <em>a[i]</em>.
* <li value="2">Remove any abstract values for field accesses <em>b.g</em> where
* <em>a[i]</em> might alias any expression in the receiver <em>b</em> and there is an
* array expression somewhere in the receiver.
* <li value="3">Remove any information about method calls.
* </ol>
*
* @param val the abstract value of the value assigned to {@code n} (or {@code null} if the
* abstract value is not known).
*/
protected void removeConflicting(FlowExpressions.ArrayAccess arrayAccess, @Nullable V val) {
Map<FlowExpressions.ArrayAccess, V> newArrayValues = new HashMap<>();
for (Entry<FlowExpressions.ArrayAccess, V> e : arrayValues.entrySet()) {
FlowExpressions.ArrayAccess otherArrayAccess = e.getKey();
V otherVal = e.getValue();
// case 1:
if (otherArrayAccess.containsModifiableAliasOf(this, arrayAccess)) {
// remove information completely
continue;
}
if (canAlias(arrayAccess.getReceiver(), otherArrayAccess.getReceiver())) {
// remove information completely
continue;
}
// information is save to be carried over
newArrayValues.put(otherArrayAccess, otherVal);
}
arrayValues = newArrayValues;
// case 2:
Map<FlowExpressions.FieldAccess, V> newFieldValues = new HashMap<>();
for (Entry<FieldAccess, V> e : fieldValues.entrySet()) {
FlowExpressions.FieldAccess otherFieldAccess = e.getKey();
V otherVal = e.getValue();
Receiver receiver = otherFieldAccess.getReceiver();
if (receiver.containsModifiableAliasOf(this, arrayAccess) && receiver.containsOfClass(ArrayAccess.class)) {
// remove information completely
continue;
}
newFieldValues.put(otherFieldAccess, otherVal);
}
fieldValues = newFieldValues;
// case 3:
methodValues = new HashMap<>();
}
use of org.checkerframework.dataflow.analysis.FlowExpressions.FieldAccess in project checker-framework by typetools.
the class CFAbstractStore method removeConflicting.
/**
* Remove any information in this store that might not be true any more after {@code
* fieldAccess} has been assigned a new value (with the abstract value {@code val}). This
* includes the following steps (assume that {@code fieldAccess} is of the form <em>a.f</em> for
* some <em>a</em>.
*
* <ol>
* <li value="1">Update the abstract value of other field accesses <em>b.g</em> where the
* field is equal (that is, <em>f=g</em>), and the receiver <em>b</em> might alias the
* receiver of {@code fieldAccess}, <em>a</em>. This update will raise the abstract value
* for such field accesses to at least {@code val} (or the old value, if that was less
* precise). However, this is only necessary if the field <em>g</em> is not final.
* <li value="2">Remove any abstract values for field accesses <em>b.g</em> where {@code
* fieldAccess} might alias any expression in the receiver <em>b</em>.
* <li value="3">Remove any information about method calls.
* <li value="4">Remove any abstract values an array access <em>b[i]</em> where {@code
* fieldAccess} might alias any expression in the receiver <em>a</em> or index <em>i</em>.
* </ol>
*
* @param val the abstract value of the value assigned to {@code n} (or {@code null} if the
* abstract value is not known).
*/
protected void removeConflicting(FlowExpressions.FieldAccess fieldAccess, @Nullable V val) {
Map<FlowExpressions.FieldAccess, V> newFieldValues = new HashMap<>();
for (Entry<FlowExpressions.FieldAccess, V> e : fieldValues.entrySet()) {
FlowExpressions.FieldAccess otherFieldAccess = e.getKey();
V otherVal = e.getValue();
// case 2:
if (otherFieldAccess.getReceiver().containsModifiableAliasOf(this, fieldAccess)) {
// remove information completely
continue;
}
// case 1:
if (fieldAccess.getField().equals(otherFieldAccess.getField())) {
if (canAlias(fieldAccess.getReceiver(), otherFieldAccess.getReceiver())) {
if (!otherFieldAccess.isFinal()) {
if (val != null) {
V newVal = val.leastUpperBound(otherVal);
newFieldValues.put(otherFieldAccess, newVal);
} else {
// remove information completely
}
continue;
}
}
}
// information is save to be carried over
newFieldValues.put(otherFieldAccess, otherVal);
}
fieldValues = newFieldValues;
Map<FlowExpressions.ArrayAccess, V> newArrayValues = new HashMap<>();
for (Entry<ArrayAccess, V> e : arrayValues.entrySet()) {
FlowExpressions.ArrayAccess otherArrayAccess = e.getKey();
V otherVal = e.getValue();
if (otherArrayAccess.containsModifiableAliasOf(this, fieldAccess)) {
// remove information completely
continue;
}
newArrayValues.put(otherArrayAccess, otherVal);
}
arrayValues = newArrayValues;
// case 3:
methodValues = new HashMap<>();
}
use of org.checkerframework.dataflow.analysis.FlowExpressions.FieldAccess in project checker-framework by typetools.
the class CFAbstractStore method updateForMethodCall.
/* --------------------------------------------------------- */
/* Handling of fields */
/* --------------------------------------------------------- */
/**
* Remove any information that might not be valid any more after a method call, and add
* information guaranteed by the method.
*
* <ol>
* <li>If the method is side-effect-free (as indicated by {@link
* org.checkerframework.dataflow.qual.SideEffectFree} or {@link
* org.checkerframework.dataflow.qual.Pure}), then no information needs to be removed.
* <li>Otherwise, all information about field accesses {@code a.f} needs to be removed, except
* if the method {@code n} cannot modify {@code a.f} (e.g., if {@code a} is a local
* variable or {@code this}, and {@code f} is final).
* <li>Furthermore, if the field has a monotonic annotation, then its information can also be
* kept.
* </ol>
*
* Furthermore, if the method is deterministic, we store its result {@code val} in the store.
*/
public void updateForMethodCall(MethodInvocationNode n, AnnotatedTypeFactory atypeFactory, V val) {
ExecutableElement method = n.getTarget().getMethod();
// case 1: remove information if necessary
if (!(analysis.checker.hasOption("assumeSideEffectFree") || isSideEffectFree(atypeFactory, method))) {
// update field values
Map<FlowExpressions.FieldAccess, V> newFieldValues = new HashMap<>();
for (Entry<FlowExpressions.FieldAccess, V> e : fieldValues.entrySet()) {
FlowExpressions.FieldAccess fieldAccess = e.getKey();
V otherVal = e.getValue();
// case 3:
List<Pair<AnnotationMirror, AnnotationMirror>> fieldAnnotations = atypeFactory.getAnnotationWithMetaAnnotation(fieldAccess.getField(), MonotonicQualifier.class);
V newOtherVal = null;
for (Pair<AnnotationMirror, AnnotationMirror> fieldAnnotation : fieldAnnotations) {
AnnotationMirror monotonicAnnotation = fieldAnnotation.second;
Name annotation = AnnotationUtils.getElementValueClassName(monotonicAnnotation, "value", false);
AnnotationMirror target = AnnotationBuilder.fromName(atypeFactory.getElementUtils(), annotation);
// Make sure the 'target' annotation is present.
if (AnnotationUtils.containsSame(otherVal.getAnnotations(), target)) {
newOtherVal = analysis.createSingleAnnotationValue(target, otherVal.getUnderlyingType()).mostSpecific(newOtherVal, null);
}
}
if (newOtherVal != null) {
// keep information for all hierarchies where we had a
// monotone annotation.
newFieldValues.put(fieldAccess, newOtherVal);
continue;
}
// case 2:
if (!fieldAccess.isUnmodifiableByOtherCode()) {
// remove information completely
continue;
}
// keep information
newFieldValues.put(fieldAccess, otherVal);
}
fieldValues = newFieldValues;
// update method values
methodValues.clear();
arrayValues.clear();
}
// store information about method call if possible
Receiver methodCall = FlowExpressions.internalReprOf(analysis.getTypeFactory(), n);
replaceValue(methodCall, val);
}
Aggregations