use of org.checkerframework.dataflow.expression.JavaExpression 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") || analysis.checker.hasOption("assumePure") || isSideEffectFree(atypeFactory, method))) {
boolean sideEffectsUnrefineAliases = ((GenericAnnotatedTypeFactory) atypeFactory).sideEffectsUnrefineAliases;
// isUnmodifiableByOtherCode. Example: @KeyFor("valueThatCanBeMutated").
if (sideEffectsUnrefineAliases) {
localVariableValues.entrySet().removeIf(e -> !e.getKey().isUnmodifiableByOtherCode());
}
// update this value
if (sideEffectsUnrefineAliases) {
thisValue = null;
}
// update field values
if (sideEffectsUnrefineAliases) {
fieldValues.entrySet().removeIf(e -> !e.getKey().isUnmodifiableByOtherCode());
} else {
Map<FieldAccess, V> newFieldValues = new HashMap<>(CollectionsPlume.mapCapacity(fieldValues));
for (Map.Entry<FieldAccess, V> e : fieldValues.entrySet()) {
FieldAccess fieldAccess = e.getKey();
V otherVal = e.getValue();
// case 3: the field has a monotonic annotation
if (!((GenericAnnotatedTypeFactory<?, ?, ?, ?>) atypeFactory).getSupportedMonotonicTypeQualifiers().isEmpty()) {
List<Pair<AnnotationMirror, AnnotationMirror>> fieldAnnotations = atypeFactory.getAnnotationWithMetaAnnotation(fieldAccess.getField(), MonotonicQualifier.class);
V newOtherVal = null;
for (Pair<AnnotationMirror, AnnotationMirror> fieldAnnotation : fieldAnnotations) {
AnnotationMirror monotonicAnnotation = fieldAnnotation.second;
// permitted for use in the framework
@SuppressWarnings("deprecation") 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.isUnassignableByOtherCode()) {
// remove information completely
continue;
}
// keep information
newFieldValues.put(fieldAccess, otherVal);
}
fieldValues = newFieldValues;
}
// update array values
arrayValues.clear();
// update method values
methodValues.keySet().removeIf(e -> !e.isUnmodifiableByOtherCode());
}
// store information about method call if possible
JavaExpression methodCall = JavaExpression.fromNode(n);
replaceValue(methodCall, val);
}
use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.
the class GenericAnnotatedTypeFactory method getExpressionAndOffsetFromJavaExpressionString.
/**
* Produces the JavaExpression and offset associated with an expression. For instance, "n+1" has
* no associated JavaExpression, but this method produces a pair of a JavaExpression (for "n") and
* an offset ("1").
*
* @param expression a Java expression, possibly with a constant offset
* @param currentPath location at which expression is evaluated
* @return the JavaExpression and offset for the given expression
* @throws JavaExpressionParseException thrown if the expression cannot be parsed
*/
public Pair<JavaExpression, String> getExpressionAndOffsetFromJavaExpressionString(String expression, TreePath currentPath) throws JavaExpressionParseException {
Pair<String, String> p = getExpressionAndOffset(expression);
JavaExpression r = parseJavaExpressionString(p.first, currentPath);
return Pair.of(r, p.second);
}
use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.
the class BaseTypeVisitor method checkPreconditions.
/**
* Checks that all the given {@code preconditions} hold true immediately prior to the method
* invocation or variable access at {@code tree}.
*
* @param tree the method invocation; immediately prior to it, the preconditions must hold true
* @param preconditions the preconditions to be checked
*/
protected void checkPreconditions(MethodInvocationTree tree, Set<Precondition> preconditions) {
// TODO: Remove this check and investigate the root cause.
if (preconditions.isEmpty()) {
return;
}
StringToJavaExpression stringToJavaExpr = stringExpr -> StringToJavaExpression.atMethodInvocation(stringExpr, tree, checker);
for (Contract c : preconditions) {
Precondition p = (Precondition) c;
String expressionString = p.expressionString;
AnnotationMirror anno = c.viewpointAdaptDependentTypeAnnotation(atypeFactory, stringToJavaExpr, tree);
JavaExpression exprJe;
try {
exprJe = StringToJavaExpression.atMethodInvocation(expressionString, tree, checker);
} catch (JavaExpressionParseException e) {
// report errors here
checker.report(tree, e.getDiagMessage());
return;
}
CFAbstractStore<?, ?> store = atypeFactory.getStoreBefore(tree);
CFAbstractValue<?> value = null;
if (CFAbstractStore.canInsertJavaExpression(exprJe)) {
value = store.getValue(exprJe);
}
AnnotationMirror inferredAnno = null;
if (value != null) {
QualifierHierarchy hierarchy = atypeFactory.getQualifierHierarchy();
Set<AnnotationMirror> annos = value.getAnnotations();
inferredAnno = hierarchy.findAnnotationInSameHierarchy(annos, anno);
}
if (!checkContract(exprJe, anno, inferredAnno, store)) {
if (exprJe != null) {
expressionString = exprJe.toString();
}
checker.reportError(tree, "contracts.precondition", tree.getMethodSelect().toString(), contractExpressionAndType(expressionString, inferredAnno), contractExpressionAndType(expressionString, anno));
}
}
}
use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.
the class BaseTypeVisitor method checkContractsAtMethodDeclaration.
/**
* Check the contracts written on a method declaration. Ensures that the postconditions hold on
* exit, and that the contracts are well-formed.
*
* @param methodTree the method declaration
* @param methodElement the method element
* @param formalParamNames the formal parameter names
* @param abstractMethod whether the method is abstract
*/
private void checkContractsAtMethodDeclaration(MethodTree methodTree, ExecutableElement methodElement, List<String> formalParamNames, boolean abstractMethod) {
Set<Contract> contracts = atypeFactory.getContractsFromMethod().getContracts(methodElement);
if (contracts.isEmpty()) {
return;
}
StringToJavaExpression stringToJavaExpr = stringExpr -> StringToJavaExpression.atMethodBody(stringExpr, methodTree, checker);
for (Contract contract : contracts) {
String expressionString = contract.expressionString;
AnnotationMirror annotation = contract.viewpointAdaptDependentTypeAnnotation(atypeFactory, stringToJavaExpr, methodTree);
JavaExpression exprJe;
try {
exprJe = StringToJavaExpression.atMethodBody(expressionString, methodTree, checker);
} catch (JavaExpressionParseException e) {
DiagMessage diagMessage = e.getDiagMessage();
if (diagMessage.getMessageKey().equals("flowexpr.parse.error")) {
String s = String.format("'%s' in the %s %s on the declaration of method '%s': ", expressionString, contract.kind.errorKey, contract.contractAnnotation.getAnnotationType().asElement().getSimpleName(), methodTree.getName().toString());
checker.reportError(methodTree, "flowexpr.parse.error", s + diagMessage.getArgs()[0]);
} else {
checker.report(methodTree, e.getDiagMessage());
}
continue;
}
if (!CFAbstractStore.canInsertJavaExpression(exprJe)) {
checker.reportError(methodTree, "flowexpr.parse.error", expressionString);
continue;
}
if (!abstractMethod && contract.kind != Contract.Kind.PRECONDITION) {
switch(contract.kind) {
case POSTCONDITION:
checkPostcondition(methodTree, annotation, exprJe);
break;
case CONDITIONALPOSTCONDITION:
checkConditionalPostcondition(methodTree, annotation, exprJe, ((ConditionalPostcondition) contract).resultValue);
break;
default:
throw new BugInCF("Impossible: " + contract.kind);
}
}
if (formalParamNames != null && formalParamNames.contains(expressionString)) {
String locationOfExpression = contract.kind.errorKey + " " + contract.contractAnnotation.getAnnotationType().asElement().getSimpleName() + " on the declaration";
checker.reportWarning(methodTree, "expression.parameter.name.shadows.field", locationOfExpression, methodTree.getName().toString(), expressionString, expressionString, formalParamNames.indexOf(expressionString) + 1);
}
checkParametersAreEffectivelyFinal(methodTree, exprJe);
}
}
use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.
the class ValueTransfer method refineAtLengthAccess.
/**
* Transform @IntVal or @IntRange annotations of a array or string length into an @ArrayLen
* or @ArrayLenRange annotation for the array or string.
*
* @param lengthNode an invocation of method {@code length} or an access of the {@code length}
* field
* @param receiverNode the receiver of {@code lengthNode}
* @param store the store to update
*/
private void refineAtLengthAccess(Node lengthNode, Node receiverNode, CFStore store) {
JavaExpression lengthExpr = JavaExpression.fromNode(lengthNode);
// not marked @Pure, then do not refine.
if (lengthExpr instanceof Unknown) {
return;
}
CFValue value = store.getValue(lengthExpr);
if (value == null) {
return;
}
AnnotationMirror lengthAnno = getValueAnnotation(value);
if (lengthAnno == null) {
return;
}
if (AnnotationUtils.areSameByName(lengthAnno, ValueAnnotatedTypeFactory.BOTTOMVAL_NAME)) {
// If the length is bottom, then this is dead code, so the receiver type
// should also be bottom.
JavaExpression receiver = JavaExpression.fromNode(receiverNode);
store.insertValue(receiver, lengthAnno);
return;
}
RangeOrListOfValues rolv;
if (atypeFactory.isIntRange(lengthAnno)) {
rolv = new RangeOrListOfValues(atypeFactory.getRange(lengthAnno));
} else if (AnnotationUtils.areSameByName(lengthAnno, ValueAnnotatedTypeFactory.INTVAL_NAME)) {
List<Long> lengthValues = atypeFactory.getIntValues(lengthAnno);
rolv = new RangeOrListOfValues(RangeOrListOfValues.convertLongsToInts(lengthValues));
} else {
return;
}
AnnotationMirror newRecAnno = rolv.createAnnotation(atypeFactory);
AnnotationMirror oldRecAnno = getArrayOrStringAnnotation(receiverNode);
AnnotationMirror combinedRecAnno;
// with the facts known about its length using GLB.
if (oldRecAnno == null) {
combinedRecAnno = newRecAnno;
} else {
combinedRecAnno = hierarchy.greatestLowerBound(oldRecAnno, newRecAnno);
}
JavaExpression receiver = JavaExpression.fromNode(receiverNode);
store.insertValue(receiver, combinedRecAnno);
}
Aggregations