use of org.checkerframework.dataflow.cfg.node.MethodInvocationNode in project checker-framework by typetools.
the class GenericAnnotatedTypeFactory method getAnnotatedTypeVarargsArray.
/**
* Returns the type of a varargs array of a method invocation or a constructor invocation. Returns
* null only if private field {@code useFlow} is false.
*
* @param tree a method invocation or a constructor invocation
* @return AnnotatedTypeMirror of varargs array for a method or constructor invocation {@code
* tree}; returns null if private field {@code useFlow} is false
*/
@Nullable
public AnnotatedTypeMirror getAnnotatedTypeVarargsArray(Tree tree) {
if (!useFlow) {
return null;
}
// Get the synthetic NewArray tree that dataflow creates as the last argument of a call to a
// vararg method. Do this by getting the MethodInvocationNode to which "tree" maps. The last
// argument node of the MethodInvocationNode stores the synthetic NewArray tree.
List<Node> args;
switch(tree.getKind()) {
case METHOD_INVOCATION:
args = getFirstNodeOfKindForTree(tree, MethodInvocationNode.class).getArguments();
break;
case NEW_CLASS:
args = getFirstNodeOfKindForTree(tree, ObjectCreationNode.class).getArguments();
break;
default:
throw new BugInCF("Unexpected kind of tree: " + tree);
}
assert !args.isEmpty() : "Arguments are empty";
Node varargsArray = args.get(args.size() - 1);
AnnotatedTypeMirror varargtype = getAnnotatedType(varargsArray.getTree());
return varargtype;
}
use of org.checkerframework.dataflow.cfg.node.MethodInvocationNode in project checker-framework by typetools.
the class CalledMethodsTransfer method handleEnsuresCalledMethodsVarArgs.
/**
* Update the types of varargs parameters passed to a method with an {@link
* EnsuresCalledMethodsVarArgs} annotation. This method is a no-op if no such annotation is
* present.
*
* @param node the method invocation node
* @param result the current result
*/
private void handleEnsuresCalledMethodsVarArgs(MethodInvocationNode node, TransferResult<CFValue, CFStore> result) {
ExecutableElement elt = TreeUtils.elementFromUse(node.getTree());
AnnotationMirror annot = atypeFactory.getDeclAnnotation(elt, EnsuresCalledMethodsVarArgs.class);
if (annot == null) {
return;
}
List<String> ensuredMethodNames = AnnotationUtils.getElementValueArray(annot, ((CalledMethodsAnnotatedTypeFactory) atypeFactory).ensuresCalledMethodsVarArgsValueElement, String.class);
List<? extends VariableElement> parameters = elt.getParameters();
int varArgsPos = parameters.size() - 1;
Node varArgActual = node.getArguments().get(varArgsPos);
// an ArrayCreationNode. This is the only case we handle for now.
if (varArgActual instanceof ArrayCreationNode) {
ArrayCreationNode arrayCreationNode = (ArrayCreationNode) varArgActual;
// add in the called method to all the vararg arguments
CFStore thenStore = result.getThenStore();
CFStore elseStore = result.getElseStore();
for (Node arg : arrayCreationNode.getInitializers()) {
AnnotatedTypeMirror currentType = atypeFactory.getAnnotatedType(arg.getTree());
AnnotationMirror newType = getUpdatedCalledMethodsType(currentType, ensuredMethodNames);
if (newType == null) {
continue;
}
JavaExpression receiverReceiver = JavaExpression.fromNode(arg);
thenStore.insertValue(receiverReceiver, newType);
elseStore.insertValue(receiverReceiver, newType);
}
}
}
use of org.checkerframework.dataflow.cfg.node.MethodInvocationNode in project checker-framework by typetools.
the class FormatterTreeUtil method asFormatCallCategoriesLowLevel.
private ConversionCategory[] asFormatCallCategoriesLowLevel(MethodInvocationNode node) {
Node vararg = node.getArgument(1);
if (!(vararg instanceof ArrayCreationNode)) {
return null;
}
List<Node> convs = ((ArrayCreationNode) vararg).getInitializers();
ConversionCategory[] res = new ConversionCategory[convs.size()];
for (int i = 0; i < convs.size(); ++i) {
Node conv = convs.get(i);
if (conv instanceof FieldAccessNode) {
Class<? extends Object> clazz = TypesUtils.getClassFromType(((FieldAccessNode) conv).getType());
if (clazz == ConversionCategory.class) {
res[i] = ConversionCategory.valueOf(((FieldAccessNode) conv).getFieldName());
continue;
/* avoid returning null */
}
}
return null;
}
return res;
}
use of org.checkerframework.dataflow.cfg.node.MethodInvocationNode in project checker-framework by typetools.
the class FlowExpressions method internalReprOf.
/**
* We ignore operations such as widening and narrowing when computing the internal
* representation.
*
* @return the internal representation (as {@link Receiver}) of any {@link Node}. Might contain
* {@link Unknown}.
*/
public static Receiver internalReprOf(AnnotationProvider provider, Node receiverNode, boolean allowNonDeterministic) {
Receiver receiver = null;
if (receiverNode instanceof FieldAccessNode) {
FieldAccessNode fan = (FieldAccessNode) receiverNode;
if (fan.getFieldName().equals("this")) {
// For some reason, "className.this" is considered a field access.
// We right this wrong here.
receiver = new ThisReference(fan.getReceiver().getType());
} else if (fan.getFieldName().equals("class")) {
// "className.class" is considered a field access. This makes sense,
// since .class is similar to a field access which is the equivalent
// of a call to getClass(). However for the purposes of dataflow
// analysis, and value stores, this is the equivalent of a ClassNameNode.
receiver = new ClassName(fan.getReceiver().getType());
} else {
receiver = internalReprOfFieldAccess(provider, fan);
}
} else if (receiverNode instanceof ExplicitThisLiteralNode) {
receiver = new ThisReference(receiverNode.getType());
} else if (receiverNode instanceof ThisLiteralNode) {
receiver = new ThisReference(receiverNode.getType());
} else if (receiverNode instanceof SuperNode) {
receiver = new ThisReference(receiverNode.getType());
} else if (receiverNode instanceof LocalVariableNode) {
LocalVariableNode lv = (LocalVariableNode) receiverNode;
receiver = new LocalVariable(lv);
} else if (receiverNode instanceof ArrayAccessNode) {
ArrayAccessNode a = (ArrayAccessNode) receiverNode;
receiver = internalReprOfArrayAccess(provider, a);
} else if (receiverNode instanceof StringConversionNode) {
// ignore string conversion
return internalReprOf(provider, ((StringConversionNode) receiverNode).getOperand());
} else if (receiverNode instanceof WideningConversionNode) {
// ignore widening
return internalReprOf(provider, ((WideningConversionNode) receiverNode).getOperand());
} else if (receiverNode instanceof NarrowingConversionNode) {
// ignore narrowing
return internalReprOf(provider, ((NarrowingConversionNode) receiverNode).getOperand());
} else if (receiverNode instanceof ClassNameNode) {
ClassNameNode cn = (ClassNameNode) receiverNode;
receiver = new ClassName(cn.getType());
} else if (receiverNode instanceof ValueLiteralNode) {
ValueLiteralNode vn = (ValueLiteralNode) receiverNode;
receiver = new ValueLiteral(vn.getType(), vn);
} else if (receiverNode instanceof ArrayCreationNode) {
ArrayCreationNode an = (ArrayCreationNode) receiverNode;
List<Receiver> dimensions = new ArrayList<>();
for (Node dimension : an.getDimensions()) {
dimensions.add(internalReprOf(provider, dimension, allowNonDeterministic));
}
List<Receiver> initializers = new ArrayList<>();
for (Node initializer : an.getInitializers()) {
initializers.add(internalReprOf(provider, initializer, allowNonDeterministic));
}
receiver = new ArrayCreation(an.getType(), dimensions, initializers);
} else if (receiverNode instanceof MethodInvocationNode) {
MethodInvocationNode mn = (MethodInvocationNode) receiverNode;
ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn.getTree());
// check if this represents a boxing operation of a constant, in which
// case we treat the method call as deterministic, because there is no way
// to behave differently in two executions where two constants are being used.
boolean considerDeterministic = false;
if (isLongValueOf(mn, invokedMethod)) {
Node arg = mn.getArgument(0);
if (arg instanceof ValueLiteralNode) {
considerDeterministic = true;
}
}
if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterministic || considerDeterministic) {
List<Receiver> parameters = new ArrayList<>();
for (Node p : mn.getArguments()) {
parameters.add(internalReprOf(provider, p));
}
Receiver methodReceiver;
if (ElementUtils.isStatic(invokedMethod)) {
methodReceiver = new ClassName(mn.getTarget().getReceiver().getType());
} else {
methodReceiver = internalReprOf(provider, mn.getTarget().getReceiver());
}
receiver = new MethodCall(mn.getType(), invokedMethod, methodReceiver, parameters);
}
}
if (receiver == null) {
receiver = new Unknown(receiverNode.getType());
}
return receiver;
}
use of org.checkerframework.dataflow.cfg.node.MethodInvocationNode in project checker-framework by typetools.
the class WholeProgramInferenceScenes method updateInferredMethodParameterTypes.
/**
* Updates the parameter types of the method methodElt in the Scene of the receiverTree's
* enclosing class based on the arguments to the method.
*
* <p>For each method parameter in methodElt:
*
* <ul>
* <li>If the Scene does not contain an annotated type for that parameter, then the type of
* the respective value passed as argument in the method call methodInvNode will be added
* to the parameter in the Scene.
* <li>If the Scene previously contained an annotated type for that parameter, then its new
* type will be the LUB between the previous type and the type of the respective value
* passed as argument in the method call.
* </ul>
*
* <p>
*
* @param methodInvNode the node representing a method invocation
* @param receiverTree the Tree of the class that contains the method being invoked
* @param methodElt the element of the method being invoked
* @param atf the annotated type factory of a given type system, whose type hierarchy will be
* used to update the method parameters' types
*/
@Override
public void updateInferredMethodParameterTypes(MethodInvocationNode methodInvNode, Tree receiverTree, ExecutableElement methodElt, AnnotatedTypeFactory atf) {
if (receiverTree == null) {
// https://github.com/typetools/checker-framework/issues/682
return;
}
ClassSymbol classSymbol = getEnclosingClassSymbol(receiverTree);
if (classSymbol == null) {
// https://github.com/typetools/checker-framework/issues/682
return;
}
// https://github.com/typetools/checker-framework/issues/682
if (!classSymbol.getEnclosedElements().contains((Symbol) methodElt)) {
return;
}
String className = classSymbol.flatname.toString();
String jaifPath = helper.getJaifPath(className);
AClass clazz = helper.getAClass(className, jaifPath);
String methodName = JVMNames.getJVMMethodName(methodElt);
AMethod method = clazz.methods.vivify(methodName);
List<Node> arguments = methodInvNode.getArguments();
updateInferredExecutableParameterTypes(methodElt, atf, jaifPath, method, arguments);
}
Aggregations