use of org.checkerframework.dataflow.expression.LocalVariable in project checker-framework by typetools.
the class LockStore method insertLockPossiblyHeld.
/*
* Insert an annotation exactly, without regard to whether an annotation was already present.
* This is only done for @LockPossiblyHeld. This is not sound for other type qualifiers.
*/
public void insertLockPossiblyHeld(JavaExpression je) {
if (je.containsUnknown()) {
// Expressions containing unknown expressions are not stored.
return;
}
if (je instanceof LocalVariable) {
LocalVariable localVar = (LocalVariable) je;
CFValue current = localVariableValues.get(localVar);
CFValue value = changeLockAnnoToTop(je, current);
if (value != null) {
localVariableValues.put(localVar, value);
}
} else if (je instanceof FieldAccess) {
FieldAccess fieldAcc = (FieldAccess) je;
CFValue current = fieldValues.get(fieldAcc);
CFValue value = changeLockAnnoToTop(je, current);
if (value != null) {
fieldValues.put(fieldAcc, value);
}
} else if (je instanceof MethodCall) {
MethodCall method = (MethodCall) je;
CFValue current = methodValues.get(method);
CFValue value = changeLockAnnoToTop(je, current);
if (value != null) {
methodValues.put(method, value);
}
} else if (je instanceof ArrayAccess) {
ArrayAccess arrayAccess = (ArrayAccess) je;
CFValue current = arrayValues.get(arrayAccess);
CFValue value = changeLockAnnoToTop(je, current);
if (value != null) {
arrayValues.put(arrayAccess, value);
}
} else if (je instanceof ThisReference) {
thisValue = changeLockAnnoToTop(je, thisValue);
} else if (je instanceof ClassName) {
ClassName className = (ClassName) je;
CFValue current = classValues.get(className);
CFValue value = changeLockAnnoToTop(je, current);
if (value != null) {
classValues.put(className, value);
}
} else {
// No other types of expressions need to be stored.
}
}
use of org.checkerframework.dataflow.expression.LocalVariable in project checker-framework by typetools.
the class CFAbstractStore method computeNewValueAndInsert.
/**
* Inserts the result of applying {@code merger} to {@code value} and the previous value for
* {@code expr}.
*
* @param expr the JavaExpression
* @param value the value of the JavaExpression
* @param merger the function used to merge {@code value} and the previous value of {@code expr}
* @param permitNondeterministic if false, does nothing if {@code expr} is nondeterministic; if
* true, permits nondeterministic expressions to be placed in the store
*/
protected void computeNewValueAndInsert(JavaExpression expr, @Nullable V value, BinaryOperator<V> merger, boolean permitNondeterministic) {
if (!shouldInsert(expr, value, permitNondeterministic)) {
return;
}
if (expr instanceof LocalVariable) {
LocalVariable localVar = (LocalVariable) expr;
V oldValue = localVariableValues.get(localVar);
V newValue = merger.apply(oldValue, value);
if (newValue != null) {
localVariableValues.put(localVar, newValue);
}
} else if (expr instanceof FieldAccess) {
FieldAccess fieldAcc = (FieldAccess) expr;
// Only store information about final fields (where the receiver is
// also fixed) if concurrent semantics are enabled.
boolean isMonotonic = isMonotonicUpdate(fieldAcc, value);
if (sequentialSemantics || isMonotonic || fieldAcc.isUnassignableByOtherCode()) {
V oldValue = fieldValues.get(fieldAcc);
V newValue = merger.apply(oldValue, value);
if (newValue != null) {
fieldValues.put(fieldAcc, newValue);
}
}
} else if (expr instanceof MethodCall) {
MethodCall method = (MethodCall) expr;
// Don't store any information if concurrent semantics are enabled.
if (sequentialSemantics) {
V oldValue = methodValues.get(method);
V newValue = merger.apply(oldValue, value);
if (newValue != null) {
methodValues.put(method, newValue);
}
}
} else if (expr instanceof ArrayAccess) {
ArrayAccess arrayAccess = (ArrayAccess) expr;
if (sequentialSemantics) {
V oldValue = arrayValues.get(arrayAccess);
V newValue = merger.apply(oldValue, value);
if (newValue != null) {
arrayValues.put(arrayAccess, newValue);
}
}
} else if (expr instanceof ThisReference) {
ThisReference thisRef = (ThisReference) expr;
if (sequentialSemantics || thisRef.isUnassignableByOtherCode()) {
V oldValue = thisValue;
V newValue = merger.apply(oldValue, value);
if (newValue != null) {
thisValue = newValue;
}
}
} else if (expr instanceof ClassName) {
ClassName className = (ClassName) expr;
if (sequentialSemantics || className.isUnassignableByOtherCode()) {
V oldValue = classValues.get(className);
V newValue = merger.apply(oldValue, value);
if (newValue != null) {
classValues.put(className, newValue);
}
}
} else {
// No other types of expressions need to be stored.
}
}
use of org.checkerframework.dataflow.expression.LocalVariable in project checker-framework by typetools.
the class CFAbstractStore method supersetOf.
/**
* Returns true iff this {@link CFAbstractStore} contains a superset of the map entries of the
* argument {@link CFAbstractStore}. Note that we test the entry keys and values by Java equality,
* not by any subtype relationship. This method is used primarily to simplify the equals
* predicate.
*/
protected boolean supersetOf(CFAbstractStore<V, S> other) {
for (Map.Entry<LocalVariable, V> e : other.localVariableValues.entrySet()) {
LocalVariable key = e.getKey();
V value = localVariableValues.get(key);
if (value == null || !value.equals(e.getValue())) {
return false;
}
}
if (!Objects.equals(thisValue, other.thisValue)) {
return false;
}
for (Map.Entry<FieldAccess, V> e : other.fieldValues.entrySet()) {
FieldAccess key = e.getKey();
V value = fieldValues.get(key);
if (value == null || !value.equals(e.getValue())) {
return false;
}
}
for (Map.Entry<ArrayAccess, V> e : other.arrayValues.entrySet()) {
ArrayAccess key = e.getKey();
V value = arrayValues.get(key);
if (value == null || !value.equals(e.getValue())) {
return false;
}
}
for (Map.Entry<MethodCall, V> e : other.methodValues.entrySet()) {
MethodCall key = e.getKey();
V value = methodValues.get(key);
if (value == null || !value.equals(e.getValue())) {
return false;
}
}
for (Map.Entry<ClassName, V> e : other.classValues.entrySet()) {
ClassName key = e.getKey();
V value = classValues.get(key);
if (value == null || !value.equals(e.getValue())) {
return false;
}
}
return true;
}
use of org.checkerframework.dataflow.expression.LocalVariable in project checker-framework by typetools.
the class CFAbstractStore method upperBound.
private S upperBound(S other, boolean shouldWiden) {
S newStore = analysis.createEmptyStore(sequentialSemantics);
for (Map.Entry<LocalVariable, V> e : other.localVariableValues.entrySet()) {
// local variables that are only part of one store, but not the other are discarded, as one of
// store implicitly contains 'top' for that variable.
LocalVariable localVar = e.getKey();
V thisVal = localVariableValues.get(localVar);
if (thisVal != null) {
V otherVal = e.getValue();
V mergedVal = upperBoundOfValues(otherVal, thisVal, shouldWiden);
if (mergedVal != null) {
newStore.localVariableValues.put(localVar, mergedVal);
}
}
}
// information about the current object
{
V otherVal = other.thisValue;
V myVal = thisValue;
V mergedVal = myVal == null ? null : upperBoundOfValues(otherVal, myVal, shouldWiden);
if (mergedVal != null) {
newStore.thisValue = mergedVal;
}
}
for (Map.Entry<FieldAccess, V> e : other.fieldValues.entrySet()) {
// information about fields that are only part of one store, but not the other are discarded,
// as one store implicitly contains 'top' for that field.
FieldAccess el = e.getKey();
V thisVal = fieldValues.get(el);
if (thisVal != null) {
V otherVal = e.getValue();
V mergedVal = upperBoundOfValues(otherVal, thisVal, shouldWiden);
if (mergedVal != null) {
newStore.fieldValues.put(el, mergedVal);
}
}
}
for (Map.Entry<ArrayAccess, V> e : other.arrayValues.entrySet()) {
// information about arrays that are only part of one store, but not the other are discarded,
// as one store implicitly contains 'top' for that array access.
ArrayAccess el = e.getKey();
V thisVal = arrayValues.get(el);
if (thisVal != null) {
V otherVal = e.getValue();
V mergedVal = upperBoundOfValues(otherVal, thisVal, shouldWiden);
if (mergedVal != null) {
newStore.arrayValues.put(el, mergedVal);
}
}
}
for (Map.Entry<MethodCall, V> e : other.methodValues.entrySet()) {
// information about methods that are only part of one store, but not the other are discarded,
// as one store implicitly contains 'top' for that field.
MethodCall el = e.getKey();
V thisVal = methodValues.get(el);
if (thisVal != null) {
V otherVal = e.getValue();
V mergedVal = upperBoundOfValues(otherVal, thisVal, shouldWiden);
if (mergedVal != null) {
newStore.methodValues.put(el, mergedVal);
}
}
}
for (Map.Entry<ClassName, V> e : other.classValues.entrySet()) {
ClassName el = e.getKey();
V thisVal = classValues.get(el);
if (thisVal != null) {
V otherVal = e.getValue();
V mergedVal = upperBoundOfValues(otherVal, thisVal, shouldWiden);
if (mergedVal != null) {
newStore.classValues.put(el, mergedVal);
}
}
}
return newStore;
}
use of org.checkerframework.dataflow.expression.LocalVariable in project checker-framework by typetools.
the class WholeProgramInferenceImplementation method updateContracts.
@Override
public void updateContracts(Analysis.BeforeOrAfter preOrPost, ExecutableElement methodElt, CFAbstractStore<?, ?> store) {
// Don't infer types for code that isn't presented as source.
if (!ElementUtils.isElementFromSourceCode(methodElt)) {
return;
}
if (store == null) {
throw new BugInCF("updateContracts(%s, %s, null) for %s", preOrPost, methodElt, atypeFactory.getClass().getSimpleName());
}
if (!storage.hasStorageLocationForMethod(methodElt)) {
return;
}
// TODO: Probably move some part of this into the AnnotatedTypeFactory.
// This code handles fields of "this" and method parameters (including the receiver parameter
// "this"), for now. In the future, extend it to other expressions.
TypeElement containingClass = (TypeElement) methodElt.getEnclosingElement();
ThisReference thisReference = new ThisReference(containingClass.asType());
ClassName classNameReceiver = new ClassName(containingClass.asType());
// Fields of "this":
for (VariableElement fieldElement : ElementFilter.fieldsIn(containingClass.getEnclosedElements())) {
if (atypeFactory.wpiOutputFormat == OutputFormat.JAIF && containingClass.getNestingKind().isNested()) {
// places the annotations incorrectly on the class declarations.
continue;
}
FieldAccess fa = new FieldAccess((ElementUtils.isStatic(fieldElement) ? classNameReceiver : thisReference), fieldElement.asType(), fieldElement);
CFAbstractValue<?> v = store.getFieldValue(fa);
AnnotatedTypeMirror fieldDeclType = atypeFactory.getAnnotatedType(fieldElement);
AnnotatedTypeMirror inferredType;
if (v != null) {
// This field is in the store.
inferredType = convertCFAbstractValueToAnnotatedTypeMirror(v, fieldDeclType);
atypeFactory.wpiAdjustForUpdateNonField(inferredType);
} else {
// This field is not in the store. Use the declared type.
inferredType = fieldDeclType;
}
T preOrPostConditionAnnos = storage.getPreOrPostconditions(preOrPost, methodElt, fa.toString(), fieldDeclType, atypeFactory);
if (preOrPostConditionAnnos == null) {
continue;
}
String file = storage.getFileForElement(methodElt);
updateAnnotationSet(preOrPostConditionAnnos, TypeUseLocation.FIELD, inferredType, fieldDeclType, file, false);
}
// This loop is 1-indexed to match the syntax used in annotation arguments.
for (int index = 1; index <= methodElt.getParameters().size(); index++) {
VariableElement paramElt = methodElt.getParameters().get(index - 1);
// spurious flowexpr.parameter.not.final warnings.
if (!ElementUtils.isEffectivelyFinal(paramElt)) {
continue;
}
LocalVariable param = new LocalVariable(paramElt);
CFAbstractValue<?> v = store.getValue(param);
AnnotatedTypeMirror declType = atypeFactory.getAnnotatedType(paramElt);
AnnotatedTypeMirror inferredType;
if (v != null) {
// This parameter is in the store.
inferredType = convertCFAbstractValueToAnnotatedTypeMirror(v, declType);
atypeFactory.wpiAdjustForUpdateNonField(inferredType);
} else {
// are supported for parameters.)
continue;
}
T preOrPostConditionAnnos = storage.getPreOrPostconditions(preOrPost, methodElt, "#" + index, declType, atypeFactory);
if (preOrPostConditionAnnos != null) {
String file = storage.getFileForElement(methodElt);
updateAnnotationSet(preOrPostConditionAnnos, TypeUseLocation.PARAMETER, inferredType, declType, file, false);
}
}
// Receiver parameter ("this"):
if (!ElementUtils.isStatic(methodElt)) {
// Static methods do not have a receiver.
CFAbstractValue<?> v = store.getValue(thisReference);
if (v != null) {
// This parameter is in the store.
AnnotatedTypeMirror declaredType = atypeFactory.getAnnotatedType(methodElt).getReceiverType();
if (declaredType == null) {
// have a receiver).
return;
}
AnnotatedTypeMirror inferredType = AnnotatedTypeMirror.createType(declaredType.getUnderlyingType(), atypeFactory, false);
inferredType.replaceAnnotations(v.getAnnotations());
atypeFactory.wpiAdjustForUpdateNonField(inferredType);
T preOrPostConditionAnnos = storage.getPreOrPostconditions(preOrPost, methodElt, "this", declaredType, atypeFactory);
if (preOrPostConditionAnnos != null) {
String file = storage.getFileForElement(methodElt);
updateAnnotationSet(preOrPostConditionAnnos, TypeUseLocation.PARAMETER, inferredType, declaredType, file, false);
}
}
}
}
Aggregations