use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.
the class MustCallTransfer method visitStringConversion.
@Override
public TransferResult<CFValue, CFStore> visitStringConversion(StringConversionNode n, TransferInput<CFValue, CFStore> p) {
// Implicit String conversions should assume that the String's type is
// whatever the default for String is, not that the conversion is polymorphic.
TransferResult<CFValue, CFStore> result = super.visitStringConversion(n, p);
LocalVariableNode temp = getOrCreateTempVar(n);
if (temp != null) {
AnnotationMirror defaultStringType = getDefaultStringType(n);
JavaExpression localExp = JavaExpression.fromNode(temp);
insertIntoStores(result, localExp, defaultStringType);
}
return result;
}
use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.
the class MustCallTransfer method visitMethodInvocation.
@Override
public TransferResult<CFValue, CFStore> visitMethodInvocation(MethodInvocationNode n, TransferInput<CFValue, CFStore> in) {
TransferResult<CFValue, CFStore> result = super.visitMethodInvocation(n, in);
updateStoreWithTempVar(result, n);
if (!atypeFactory.getChecker().hasOption(MustCallChecker.NO_CREATES_MUSTCALLFOR)) {
List<JavaExpression> targetExprs = CreatesMustCallForElementSupplier.getCreatesMustCallForExpressions(n, atypeFactory, atypeFactory);
for (JavaExpression targetExpr : targetExprs) {
AnnotationMirror defaultType = atypeFactory.getAnnotatedType(TypesUtils.getTypeElement(targetExpr.getType())).getAnnotationInHierarchy(atypeFactory.TOP);
if (result.containsTwoStores()) {
CFStore thenStore = result.getThenStore();
lubWithStoreValue(thenStore, targetExpr, defaultType);
CFStore elseStore = result.getElseStore();
lubWithStoreValue(elseStore, targetExpr, defaultType);
} else {
CFStore store = result.getRegularStore();
lubWithStoreValue(store, targetExpr, defaultType);
}
}
}
return result;
}
use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.
the class MustCallTransfer method updateStoreWithTempVar.
/**
* This method either creates or looks up the temp var t for node, and then updates the store to
* give t the same type as {@code node}.
*
* @param node the node to be assigned to a temporary variable
* @param result the transfer result containing the store to be modified
*/
public void updateStoreWithTempVar(TransferResult<CFValue, CFStore> result, Node node) {
// Must-call obligations on primitives are not supported.
if (!TypesUtils.isPrimitiveOrBoxed(node.getType())) {
LocalVariableNode temp = getOrCreateTempVar(node);
if (temp != null) {
JavaExpression localExp = JavaExpression.fromNode(temp);
AnnotationMirror anm = atypeFactory.getAnnotatedType(node.getTree()).getAnnotationInHierarchy(atypeFactory.TOP);
insertIntoStores(result, localExp, anm == null ? atypeFactory.TOP : anm);
}
}
}
use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.
the class AccumulationTransfer method accumulate.
/**
* Updates the estimate of how many things {@code node} has accumulated.
*
* <p>If the node is an invocation of a method that returns its receiver, then its receiver's type
* will also be updated. In a chain of method calls, this process will continue backward as long
* as each receiver is itself a receiver-returning method invocation.
*
* <p>For example, suppose {@code node} is the expression {@code a.b().c()}, the new value (added
* by the accumulation analysis because of the {@code .c()} call) is "foo", and b and c return
* their receiver. This method will directly update the estimate of {@code a.b().c()} to include
* "foo". In addition, the estimates for the expressions {@code a.b()} and {@code a} would have
* their estimates updated to include "foo", because c and b (respectively) return their
* receivers. Note that due to what kind of values can be held in the store, this information is
* lost outside the method chain. That is, the returns-receiver propagated information is lost
* outside the expression in which the returns-receiver method invocations are nested.
*
* <p>As a concrete example, consider the Called Methods accumulation checker: if {@code build}
* requires a, b, and c to be called, then {@code foo.a().b().c().build();} will typecheck (they
* are in one fluent method chain), but {@code foo.a().b().c(); foo.build();} will not -- the
* store does not keep the information that a, b, and c have been called outside the chain. {@code
* foo}'s type will be {@code CalledMethods("a")}, because only {@code a()} was called directly on
* {@code foo}. For such code to typecheck, the Called Methods accumulation checker uses an
* additional rule: the return type of a receiver-returning method {@code rr()} is {@code
* CalledMethods("rr")}. This rule is implemented directly in the {@link
* org.checkerframework.framework.type.treeannotator.TreeAnnotator} subclass defined in the Called
* Methods type factory.
*
* @param node the node whose estimate should be expanded
* @param result the transfer result containing the store to be modified
* @param values the new accumulation values
*/
public void accumulate(Node node, TransferResult<CFValue, CFStore> result, String... values) {
List<String> valuesAsList = Arrays.asList(values);
// If dataflow has already recorded information about the target, fetch it and integrate
// it into the list of values in the new annotation.
JavaExpression target = JavaExpression.fromNode(node);
if (CFAbstractStore.canInsertJavaExpression(target)) {
CFValue flowValue = result.getRegularStore().getValue(target);
if (flowValue != null) {
Set<AnnotationMirror> flowAnnos = flowValue.getAnnotations();
assert flowAnnos.size() <= 1;
for (AnnotationMirror anno : flowAnnos) {
if (atypeFactory.isAccumulatorAnnotation(anno)) {
List<String> oldFlowValues = atypeFactory.getAccumulatedValues(anno);
if (!oldFlowValues.isEmpty()) {
// valuesAsList cannot have its length changed -- it is backed by an
// array -- but if oldFlowValues is not empty, it is a new, modifiable list.
oldFlowValues.addAll(valuesAsList);
valuesAsList = oldFlowValues;
}
}
}
}
}
AnnotationMirror newAnno = atypeFactory.createAccumulatorAnnotation(valuesAsList);
insertIntoStores(result, target, newAnno);
Tree tree = node.getTree();
if (tree != null && tree.getKind() == Tree.Kind.METHOD_INVOCATION) {
Node receiver = ((MethodInvocationNode) node).getTarget().getReceiver();
if (receiver != null && atypeFactory.returnsThis((MethodInvocationTree) tree)) {
accumulate(receiver, result, values);
}
}
}
use of org.checkerframework.dataflow.expression.JavaExpression in project checker-framework by typetools.
the class AliasingTransfer method visitAssignment.
/**
* Case 1: For every assignment, the LHS is refined if the RHS has type {@literal @}Unique and is
* a method invocation or a new class instance.
*/
@Override
public TransferResult<CFValue, CFStore> visitAssignment(AssignmentNode n, TransferInput<CFValue, CFStore> in) {
Node rhs = n.getExpression();
Tree treeRhs = rhs.getTree();
AnnotatedTypeMirror rhsType = factory.getAnnotatedType(treeRhs);
if (rhsType.hasAnnotation(Unique.class) && (rhs instanceof MethodInvocationNode || rhs instanceof ObjectCreationNode)) {
// Do normal refinement.
return super.visitAssignment(n, in);
}
// Widen the type of the rhs if the RHS's declared type wasn't @Unique.
JavaExpression rhsExpr = JavaExpression.fromNode(rhs);
in.getRegularStore().clearValue(rhsExpr);
return new RegularTransferResult<>(null, in.getRegularStore());
}
Aggregations