diff --git a/libsolidity/formal/BMC.cpp b/libsolidity/formal/BMC.cpp index 21a001d04..49a67d75c 100644 --- a/libsolidity/formal/BMC.cpp +++ b/libsolidity/formal/BMC.cpp @@ -76,47 +76,32 @@ void BMC::analyze(SourceUnit const& _source, shared_ptr const& _scanner m_errorReporter.clear(); } -FunctionDefinition const* BMC::inlinedFunctionCallToDefinition(FunctionCall const& _funCall) +bool BMC::shouldInlineFunctionCall(FunctionCall const& _funCall) { - if (_funCall.annotation().kind != FunctionCallKind::FunctionCall) - return nullptr; + FunctionDefinition const* funDef = functionCallToDefinition(_funCall); + if (!funDef || !funDef->isImplemented()) + return false; FunctionType const& funType = dynamic_cast(*_funCall.expression().annotation().type); if (funType.kind() == FunctionType::Kind::External) { auto memberAccess = dynamic_cast(&_funCall.expression()); - auto identifier = memberAccess ? - dynamic_cast(&memberAccess->expression()) : - nullptr; + if (!memberAccess) + return false; + + auto identifier = dynamic_cast(&memberAccess->expression()); if (!( identifier && identifier->name() == "this" && identifier->annotation().referencedDeclaration && dynamic_cast(identifier->annotation().referencedDeclaration) )) - return nullptr; + return false; } else if (funType.kind() != FunctionType::Kind::Internal) - return nullptr; + return false; - FunctionDefinition const* funDef = nullptr; - Expression const* calledExpr = &_funCall.expression(); - - if (TupleExpression const* fun = dynamic_cast(&_funCall.expression())) - { - solAssert(fun->components().size() == 1, ""); - calledExpr = fun->components().front().get(); - } - - if (Identifier const* fun = dynamic_cast(calledExpr)) - funDef = dynamic_cast(fun->annotation().referencedDeclaration); - else if (MemberAccess const* fun = dynamic_cast(calledExpr)) - funDef = dynamic_cast(fun->annotation().referencedDeclaration); - - if (funDef && funDef->isImplemented()) - return funDef; - - return nullptr; + return true; } /// AST visitors. @@ -403,7 +388,8 @@ void BMC::visitRequire(FunctionCall const& _funCall) void BMC::inlineFunctionCall(FunctionCall const& _funCall) { - FunctionDefinition const* funDef = inlinedFunctionCallToDefinition(_funCall); + solAssert(shouldInlineFunctionCall(_funCall), ""); + FunctionDefinition const* funDef = functionCallToDefinition(_funCall); solAssert(funDef, ""); if (visitedFunction(funDef)) m_errorReporter.warning( @@ -468,9 +454,8 @@ void BMC::abstractFunctionCall(FunctionCall const& _funCall) void BMC::internalOrExternalFunctionCall(FunctionCall const& _funCall) { - auto funDef = inlinedFunctionCallToDefinition(_funCall); auto const& funType = dynamic_cast(*_funCall.expression().annotation().type); - if (funDef) + if (shouldInlineFunctionCall(_funCall)) inlineFunctionCall(_funCall); else if (funType.kind() == FunctionType::Kind::Internal) m_errorReporter.warning( diff --git a/libsolidity/formal/BMC.h b/libsolidity/formal/BMC.h index 28ea2117e..7bff69cdf 100644 --- a/libsolidity/formal/BMC.h +++ b/libsolidity/formal/BMC.h @@ -62,9 +62,8 @@ public: /// the constructor. std::vector unhandledQueries() { return m_interface->unhandledQueries(); } - /// @returns the FunctionDefinition of a called function if possible and should inline, - /// otherwise nullptr. - static FunctionDefinition const* inlinedFunctionCallToDefinition(FunctionCall const& _funCall); + /// @returns true if _funCall should be inlined, otherwise false. + static bool shouldInlineFunctionCall(FunctionCall const& _funCall); std::shared_ptr solver() { return m_interface; } diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 45694c187..792b27b35 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -1354,3 +1354,25 @@ string SMTEncoder::extraComment() "You can re-introduce information using require()."; return extra; } + +FunctionDefinition const* SMTEncoder::functionCallToDefinition(FunctionCall const& _funCall) +{ + if (_funCall.annotation().kind != FunctionCallKind::FunctionCall) + return nullptr; + + FunctionDefinition const* funDef = nullptr; + Expression const* calledExpr = &_funCall.expression(); + + if (TupleExpression const* fun = dynamic_cast(&_funCall.expression())) + { + solAssert(fun->components().size() == 1, ""); + calledExpr = fun->components().front().get(); + } + + if (Identifier const* fun = dynamic_cast(calledExpr)) + funDef = dynamic_cast(fun->annotation().referencedDeclaration); + else if (MemberAccess const* fun = dynamic_cast(calledExpr)) + funDef = dynamic_cast(fun->annotation().referencedDeclaration); + + return funDef; +} diff --git a/libsolidity/formal/SMTEncoder.h b/libsolidity/formal/SMTEncoder.h index 60dd67bb7..4d61d6f44 100644 --- a/libsolidity/formal/SMTEncoder.h +++ b/libsolidity/formal/SMTEncoder.h @@ -55,6 +55,10 @@ public: /// @returns the leftmost identifier in a multi-d IndexAccess. static Expression const* leftmostBase(IndexAccess const& _indexAccess); + /// @returns the FunctionDefinition of a FunctionCall + /// if possible or nullptr. + static FunctionDefinition const* functionCallToDefinition(FunctionCall const& _funCall); + protected: // TODO: Check that we do not have concurrent reads and writes to a variable, // because the order of expression evaluation is undefined diff --git a/libsolidity/formal/VariableUsage.cpp b/libsolidity/formal/VariableUsage.cpp index 59729be2a..585072d3b 100644 --- a/libsolidity/formal/VariableUsage.cpp +++ b/libsolidity/formal/VariableUsage.cpp @@ -58,9 +58,12 @@ void VariableUsage::endVisit(IndexAccess const& _indexAccess) void VariableUsage::endVisit(FunctionCall const& _funCall) { if (m_inlineFunctionCalls) - if (auto const& funDef = BMC::inlinedFunctionCallToDefinition(_funCall)) + if (auto const& funDef = SMTEncoder::functionCallToDefinition(_funCall)) + { + solAssert(funDef, ""); if (find(m_callStack.begin(), m_callStack.end(), funDef) == m_callStack.end()) funDef->accept(*this); + } } bool VariableUsage::visit(FunctionDefinition const& _function)