diff --git a/libsolidity/analysis/FunctionCallGraph.cpp b/libsolidity/analysis/FunctionCallGraph.cpp index f291c0bee..0e695c7ec 100644 --- a/libsolidity/analysis/FunctionCallGraph.cpp +++ b/libsolidity/analysis/FunctionCallGraph.cpp @@ -108,6 +108,26 @@ unique_ptr FunctionCallGraphBuilder return FunctionCallGraphBuilder(_contract).m_graph; } +bool FunctionCallGraphBuilder::visit(FunctionCall const& _functionCall) +{ + solAssert(m_currentNode.has_value(), ""); + solAssert(holds_alternative(*m_currentNode) || get(*m_currentNode) != nullptr, ""); + + FunctionType const* functionType = dynamic_cast(_functionCall.expression().annotation().type); + if ( + functionType && + functionType->kind() == FunctionType::Kind::Internal && + !_functionCall.expression().annotation().calledDirectly + ) + // If it's not a direct call, we don't really know which function will be called (it may even + // change at runtime). All we can do is to add an edge to the dispatch which in turn has + // edges to all functions could possibly be called. + add(*m_currentNode, m_currentDispatch); + + + return true; +} + bool FunctionCallGraphBuilder::visit(Identifier const& _identifier) { if (auto const* callable = dynamic_cast(_identifier.annotation().referencedDeclaration)) @@ -199,12 +219,8 @@ void FunctionCallGraphBuilder::processFunction(CallableDeclaration const& _calla if (_calledDirectly) add(*m_currentNode, &_callable); else - { add(m_currentDispatch, &_callable); - add(&_callable, m_currentDispatch); - } - if (!m_graph->edges.count(&_callable)) visitCallable(&_callable); } diff --git a/libsolidity/analysis/FunctionCallGraph.h b/libsolidity/analysis/FunctionCallGraph.h index 1c4e79838..bd9043812 100644 --- a/libsolidity/analysis/FunctionCallGraph.h +++ b/libsolidity/analysis/FunctionCallGraph.h @@ -83,6 +83,7 @@ public: private: FunctionCallGraphBuilder(ContractDefinition const& _contract); + bool visit(FunctionCall const& _functionCall) override; bool visit(Identifier const& _identifier) override; bool visit(NewExpression const& _newExpression) override; void endVisit(MemberAccess const& _memberAccess) override;