in Sources/SolToBoogie/ProcedureTranslator.cs [2331:2492]
public override bool Visit(FunctionCall node)
{
preTranslationAction(node);
// VeriSolAssert(!(node.Expression is NewExpression), $"new expressions should be handled in assignment");
if (node.Expression is NewExpression)
{
BoogieIdentifierExpr tmpVarExpr = MkNewLocalVariableForFunctionReturn(node);
TranslateNewStatement(node, tmpVarExpr);
currentExpr = tmpVarExpr;
return false;
}
var functionName = TransUtils.GetFuncNameFromFuncCall(node);
if (functionName.Equals("assert"))
{
// TODO:
//countNestedFuncCallsRelExprs--;
VeriSolAssert(node.Arguments.Count == 1);
BoogieExpr predicate = TranslateExpr(node.Arguments[0]);
BoogieAssertCmd assertCmd = new BoogieAssertCmd(predicate);
currentStmtList.AddStatement(assertCmd);
}
else if (functionName.Equals("require"))
{
// TODO:
//countNestedFuncCallsRelExprs--;
VeriSolAssert(node.Arguments.Count == 1 || node.Arguments.Count == 2);
BoogieExpr predicate = TranslateExpr(node.Arguments[0]);
if (!context.TranslateFlags.ModelReverts)
{
BoogieAssumeCmd assumeCmd = new BoogieAssumeCmd(predicate);
currentStmtList.AddStatement(assumeCmd);
}
else
{
BoogieStmtList revertLogic = new BoogieStmtList();
emitRevertLogic(revertLogic);
BoogieIfCmd requierCheck = new BoogieIfCmd(new BoogieUnaryOperation(BoogieUnaryOperation.Opcode.NOT, predicate), revertLogic, null);
currentStmtList.AddStatement(requierCheck);
}
}
else if (functionName.Equals("revert"))
{
VeriSolAssert(node.Arguments.Count == 0 || node.Arguments.Count == 1);
if (!context.TranslateFlags.ModelReverts)
{
BoogieAssumeCmd assumeCmd = new BoogieAssumeCmd(new BoogieLiteralExpr(false));
currentStmtList.AddStatement(assumeCmd);
}
else
{
emitRevertLogic(currentStmtList);
}
}
else if (IsImplicitFunc(node))
{
BoogieIdentifierExpr tmpVarExpr = MkNewLocalVariableForFunctionReturn(node);
bool isElementaryCast = false;
if (IsContractConstructor(node)) {
TranslateNewStatement(node, tmpVarExpr);
} else if (IsTypeCast(node)) {
TranslateTypeCast(node, tmpVarExpr, out isElementaryCast);
} else if (IsAbiEncodePackedFunc(node)) {
TranslateAbiEncodedFuncCall(node, tmpVarExpr);
} else if (IsKeccakFunc(node)) {
TranslateKeccakFuncCall(node, tmpVarExpr);
} else if (IsStructConstructor(node)) {
TranslateStructConstructor(node, tmpVarExpr);
} else
{
VeriSolAssert(false, $"Unexpected implicit function {node.ToString()}");
}
if (!isElementaryCast)
{
// We should not introduce temporaries for address(this).balance in a specification
currentExpr = tmpVarExpr;
}
}
else if (IsVeriSolCodeContractFunction(node))
{
// we cannot use temporaries as we are translating a specification
currentExpr = TranslateVeriSolCodeContractFuncCall(node);
}
else if (context.HasEventNameInContract(currentContract, functionName))
{
// generate empty statement list to ignore the event call
List<BoogieAttribute> attributes = new List<BoogieAttribute>()
{
new BoogieAttribute("EventEmitted", "\"" + functionName + "_" + currentContract.Name + "\""),
};
currentStmtList.AddStatement(new BoogieAssertCmd(new BoogieLiteralExpr(true), attributes));
}
else if (functionName.Equals("call"))
{
TranslateCallStatement(node);
}
else if (functionName.Equals("delegatecall"))
{
VeriSolAssert(false, "low-level delegatecall statements not supported...");
}
else if (IsBuiltInTransferFunc(functionName, node))
{
TranslateTransferCallStmt(node);
}
else if (functionName.Equals("send"))
{
var tmpVarExpr = MkNewLocalVariableForFunctionReturn(node);
var amountExpr = TranslateExpr(node.Arguments[0]);
TranslateSendCallStmt(node, tmpVarExpr, amountExpr);
currentExpr = tmpVarExpr;
}
else if (IsDynamicArrayPush(node))
{
TranslateDynamicArrayPush(node);
}
else if (IsExternalFunctionCall(node))
{
// external function calls
var memberAccess = node.Expression as MemberAccess;
VeriSolAssert(memberAccess != null, $"An external function has to be a member access, found {node.ToString()}");
// HACK: this is the way to identify the return type is void and hence don't need temporary variable
if (node.TypeDescriptions.TypeString != "tuple()")
{
var tmpVarExpr = MkNewLocalVariableForFunctionReturn(node);
var outParams = new List<BoogieIdentifierExpr>() { tmpVarExpr };
TranslateExternalFunctionCall(node, outParams);
currentExpr = tmpVarExpr;
}
else
{
TranslateExternalFunctionCall(node);
}
}
else // internal function calls
{
// HACK: this is the way to identify the return type is void and hence don't need temporary variable
if (node.TypeDescriptions.TypeString != "tuple()")
{
// internal function calls
var tmpVarExpr = MkNewLocalVariableForFunctionReturn(node);
var outParams = new List<BoogieIdentifierExpr>() { tmpVarExpr };
TranslateInternalFunctionCall(node, outParams);
currentExpr = tmpVarExpr;
}
else
{
TranslateInternalFunctionCall(node);
}
}
return false;
}