use of org.checkerframework.dataflow.analysis.FlowExpressions.Receiver 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.Receiver 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);
}
use of org.checkerframework.dataflow.analysis.FlowExpressions.Receiver in project checker-framework by typetools.
the class FlowExpressionParseUtil method parseMemberSelect.
private static Receiver parseMemberSelect(String s, ProcessingEnvironment env, FlowExpressionContext context, TreePath path) throws FlowExpressionParseException {
Pair<String, String> select = parseMemberSelect(s);
assert select != null : "isMemberSelect must be called first";
Receiver receiver;
String memberSelected;
Resolver resolver = new Resolver(env);
// Attempt to match a package and class name first.
Pair<ClassName, String> classAndRemainingString = matchPackageAndClassNameWithinExpression(s, resolver, path);
if (classAndRemainingString != null) {
receiver = classAndRemainingString.first;
memberSelected = classAndRemainingString.second;
if (memberSelected == null) {
throw constructParserException(s, "a class cannot terminate a flow expression string");
}
} else {
String receiverString = select.first;
memberSelected = select.second;
receiver = parseHelper(receiverString, context, path);
}
if (memberSelected.equals("class")) {
if (receiver instanceof FlowExpressions.ClassName && !context.parsingMember) {
return receiver;
} else {
throw constructParserException(s, "class is not a legal identifier");
}
}
// Parse the rest, with a new receiver.
FlowExpressionContext newContext = context.copyChangeToParsingMemberOfReceiver(receiver);
return parseHelper(memberSelected, newContext, path);
}
use of org.checkerframework.dataflow.analysis.FlowExpressions.Receiver in project checker-framework by typetools.
the class FlowExpressionParseUtil method parseMethod.
private static Receiver parseMethod(String s, FlowExpressionContext context, TreePath path, ProcessingEnvironment env) throws FlowExpressionParseException {
Pair<Pair<String, String>, String> method = parseMethod(s);
if (method == null) {
return null;
}
String methodName = method.first.first;
// parse parameter list
String parameterList = method.first.second;
List<Receiver> parameters = ParameterListParser.parseParameterList(parameterList, true, context.copyAndUseOuterReceiver(), path);
// get types for parameters
List<TypeMirror> parameterTypes = new ArrayList<>();
for (Receiver p : parameters) {
parameterTypes.add(p.getType());
}
ExecutableElement methodElement = null;
try {
Element element = null;
// try to find the correct method
Resolver resolver = new Resolver(env);
TypeMirror receiverType = context.receiver.getType();
if (receiverType.getKind() == TypeKind.ARRAY) {
element = resolver.findMethod(methodName, receiverType, path, parameterTypes);
}
// Search for method in each enclosing class.
while (receiverType.getKind() == TypeKind.DECLARED) {
element = resolver.findMethod(methodName, receiverType, path, parameterTypes);
if (element.getKind() == ElementKind.METHOD) {
break;
}
receiverType = getTypeOfEnclosingClass((DeclaredType) receiverType);
}
if (element == null) {
throw constructParserException(s, "element==null");
}
if (element.getKind() != ElementKind.METHOD) {
throw constructParserException(s, "element.getKind()==" + element.getKind());
}
methodElement = (ExecutableElement) element;
for (int i = 0; i < parameters.size(); i++) {
VariableElement formal = methodElement.getParameters().get(i);
TypeMirror formalType = formal.asType();
Receiver actual = parameters.get(i);
TypeMirror actualType = actual.getType();
// boxing necessary
if (TypesUtils.isBoxedPrimitive(formalType) && TypesUtils.isPrimitive(actualType)) {
MethodSymbol valueOfMethod = TreeBuilder.getValueOfMethod(env, formalType);
List<Receiver> p = new ArrayList<>();
p.add(actual);
Receiver boxedParam = new MethodCall(formalType, valueOfMethod, new ClassName(formalType), p);
parameters.set(i, boxedParam);
}
}
} catch (Throwable t) {
throw constructParserException(s, t);
}
assert methodElement != null;
/*if (!PurityUtils.isDeterministic(context.checkerContext.getAnnotationProvider(),
methodElement)) {
throw new FlowExpressionParseException(Result.failure(
"flowexpr.method.not.deterministic",
methodElement.getSimpleName()));
}*/
if (ElementUtils.isStatic(methodElement)) {
Element classElem = methodElement.getEnclosingElement();
Receiver staticClassReceiver = new ClassName(ElementUtils.getType(classElem));
return new MethodCall(ElementUtils.getType(methodElement), methodElement, staticClassReceiver, parameters);
} else {
if (context.receiver instanceof ClassName) {
throw constructParserException(s, "a non-static method call cannot have a class name as a receiver.");
}
TypeMirror methodType = TypesUtils.substituteMethodReturnType(methodElement, context.receiver.getType(), env);
return new MethodCall(methodType, methodElement, context.receiver, parameters);
}
}
use of org.checkerframework.dataflow.analysis.FlowExpressions.Receiver in project checker-framework by typetools.
the class FlowExpressionParseUtil method internalReprOfVariable.
public static Receiver internalReprOfVariable(AnnotatedTypeFactory provider, VariableTree tree) throws FlowExpressionParseException {
Element elt = TreeUtils.elementFromDeclaration(tree);
if (elt.getKind() == ElementKind.LOCAL_VARIABLE || elt.getKind() == ElementKind.RESOURCE_VARIABLE || elt.getKind() == ElementKind.EXCEPTION_PARAMETER || elt.getKind() == ElementKind.PARAMETER) {
return new LocalVariable(elt);
}
Receiver receiverF = FlowExpressions.internalReprOfImplicitReceiver(elt);
FlowExpressionParseUtil.FlowExpressionContext context = new FlowExpressionParseUtil.FlowExpressionContext(receiverF, null, provider.getContext());
return FlowExpressionParseUtil.parse(tree.getName().toString(), context, provider.getPath(tree), false);
}
Aggregations