fixup! Syntactic call graph

This commit is contained in:
Nikola Matic 2023-10-02 15:50:36 +02:00
parent 9656cf105b
commit ccae691606
5 changed files with 17 additions and 41 deletions

View File

@ -99,14 +99,14 @@ private:
/// Starts at @a _entry and parses the control flow of @a _node.
/// @returns The node at which the parsed control flow ends.
/// m_currentNode is not affected (it is saved and restored).
/// m_currentFunction is not affected (it is saved and restored).
CFGNode* createFlow(CFGNode* _entry, ASTNode const& _node);
/// Creates an arc from @a _from to @a _to.
static void connect(CFGNode* _from, CFGNode* _to);
/// Splits the control flow starting at the current node into n paths.
/// m_currentNode is set to nullptr and has to be set manually or
/// m_currentFunction is set to nullptr and has to be set manually or
/// using mergeFlow later.
template<size_t n>
std::array<CFGNode*, n> splitFlow()
@ -122,7 +122,7 @@ private:
}
/// Splits the control flow starting at the current node into @a _n paths.
/// m_currentNode is set to nullptr and has to be set manually or
/// m_currentFunction is set to nullptr and has to be set manually or
/// using mergeFlow later.
std::vector<CFGNode*> splitFlow(size_t n)
{

View File

@ -23,10 +23,9 @@ using namespace solidity::frontend::experimental;
using namespace solidity::util;
FunctionCallGraph::FunctionCallGraph(solidity::frontend::experimental::Analysis& _analysis):
m_analysis(_analysis),
m_errorReporter(_analysis.errorReporter()),
m_currentNode(nullptr),
m_inFunctionDefinition(false)
m_analysis(_analysis),
m_errorReporter(_analysis.errorReporter()),
m_currentFunction(nullptr)
{
}
@ -40,8 +39,9 @@ bool FunctionCallGraph::analyze(SourceUnit const& _sourceUnit)
bool FunctionCallGraph::visit(FunctionDefinition const& _functionDefinition)
{
solAssert(!m_inFunctionDefinition && !m_currentFunction);
m_inFunctionDefinition = true;
m_currentNode = &_functionDefinition;
m_currentFunction = &_functionDefinition;
return true;
}
@ -49,36 +49,28 @@ void FunctionCallGraph::endVisit(FunctionDefinition const&)
{
// If we're done visiting a function declaration without said function referencing/calling
// another function in its body - insert it into the graph without child nodes.
if (!annotation().functionCallGraph.edges.count(m_currentNode))
{
annotation().functionCallGraph.edges.insert({m_currentNode, {}});
annotation().functionCallGraph.reverseEdges[nullptr].insert(m_currentNode);
}
if (!annotation().functionCallGraph.edges.count(m_currentFunction))
annotation().functionCallGraph.edges.insert({m_currentFunction, {}});
m_inFunctionDefinition = false;
m_currentFunction = nullptr;
}
bool FunctionCallGraph::visit(Identifier const& _identifier)
{
auto callee = dynamic_cast<FunctionDefinition const*>(_identifier.annotation().referencedDeclaration);
// Check that the identifier is within a function body and is a function, and add it to the graph
// as an ``m_currentNode`` -> ``callee`` edge.
if (m_inFunctionDefinition && _identifier.annotation().referencedDeclaration && callee)
// as an ``m_currentFunction`` -> ``callee`` edge.
if (m_inFunctionDefinition && callee)
{
solAssert(m_currentNode, "Child node must have a parent");
add(m_currentNode, callee);
solAssert(m_currentFunction, "Child node must have a parent");
add(m_currentFunction, callee);
}
return true;
}
void FunctionCallGraph::add(FunctionDefinition const* _caller, FunctionDefinition const* _callee)
{
// Add caller and callee as and edge, as well as the reverse edge, i.e. callee -> caller.
// If the caller is already in the reverse edges as a childless node, remove it, since it now
// has a child.
annotation().functionCallGraph.edges[_caller].insert(_callee);
annotation().functionCallGraph.reverseEdges[_callee].insert(_caller);
if (annotation().functionCallGraph.reverseEdges[nullptr].count(_caller) > 0)
annotation().functionCallGraph.reverseEdges[nullptr].erase(_caller);
}
FunctionCallGraph::GlobalAnnotation& FunctionCallGraph::annotation()

View File

@ -51,8 +51,8 @@ private:
Analysis& m_analysis;
langutil::ErrorReporter& m_errorReporter;
FunctionDefinition const* m_currentNode;
bool m_inFunctionDefinition;
FunctionDefinition const* m_currentFunction;
bool m_inFunctionDefinition = false;
};
}

View File

@ -35,20 +35,5 @@ std::ostream& solidity::frontend::experimental::operator<<(std::ostream& _out, C
}
_out << "}" << std::endl;
}
_out << "\nREVERSE EDGES" << "\n";
_out << "===================" << std::endl;
for (auto [top, subs]: _callGraph.reverseEdges)
{
std::string topName = top ? top->name() : "nullptr";
_out << "(" << topName <<") --> {";
for (auto sub: subs)
{
std::string subName = sub->name().empty() ? "fallback" : sub->name();
_out << subName << ",";
}
_out << "}" << std::endl;
}
return _out;
}

View File

@ -35,7 +35,6 @@ struct CallGraph
/// The map contains a key for every possible caller, even if does not actually perform
/// any calls.
std::map<FunctionDefinition const*, std::set<FunctionDefinition const*>> edges;
std::map<FunctionDefinition const*, std::set<FunctionDefinition const*>> reverseEdges;
};
std::ostream& operator<<(std::ostream& _out, CallGraph const& _callGraph);