the corresponding files to avoid confusion. This is a preparation to adding an AST-based call graph to Analysis. The existing call graph works with indexer entries. We might be able to refactor it to use the AST based graph in the future. (Minimal testing here as the only example that uses the API has been completely broken, does not compile.) llvm-svn: 151950
153 lines
3.9 KiB
C++
153 lines
3.9 KiB
C++
//== GlobalCallGraph.cpp - Call graph building ------------------*- C++ -*--==//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defined the CallGraph and CGBuilder classes.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Index/GlobalCallGraph.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/StmtVisitor.h"
|
|
|
|
#include "llvm/Support/GraphWriter.h"
|
|
|
|
using namespace clang::idx;
|
|
using clang::FunctionDecl;
|
|
using clang::DeclContext;
|
|
using clang::ASTContext;
|
|
|
|
namespace {
|
|
class CGBuilder : public StmtVisitor<CGBuilder> {
|
|
|
|
CallGraph &G;
|
|
FunctionDecl *FD;
|
|
|
|
Entity CallerEnt;
|
|
|
|
CallGraphNode *CallerNode;
|
|
|
|
public:
|
|
CGBuilder(CallGraph &g, FunctionDecl *fd, Entity E, CallGraphNode *N)
|
|
: G(g), FD(fd), CallerEnt(E), CallerNode(N) {}
|
|
|
|
void VisitStmt(Stmt *S) { VisitChildren(S); }
|
|
|
|
void VisitCallExpr(CallExpr *CE);
|
|
|
|
void VisitChildren(Stmt *S) {
|
|
for (Stmt::child_range I = S->children(); I; ++I)
|
|
if (*I)
|
|
static_cast<CGBuilder*>(this)->Visit(*I);
|
|
}
|
|
};
|
|
}
|
|
|
|
void CGBuilder::VisitCallExpr(CallExpr *CE) {
|
|
if (FunctionDecl *CalleeDecl = CE->getDirectCallee()) {
|
|
Entity Ent = Entity::get(CalleeDecl, G.getProgram());
|
|
CallGraphNode *CalleeNode = G.getOrInsertFunction(Ent);
|
|
CallerNode->addCallee(ASTLocation(FD, CE), CalleeNode);
|
|
}
|
|
}
|
|
|
|
CallGraph::CallGraph(Program &P) : Prog(P), Root(0) {
|
|
ExternalCallingNode = getOrInsertFunction(Entity());
|
|
}
|
|
|
|
CallGraph::~CallGraph() {
|
|
if (!FunctionMap.empty()) {
|
|
for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
|
|
I != E; ++I)
|
|
delete I->second;
|
|
FunctionMap.clear();
|
|
}
|
|
}
|
|
|
|
void CallGraph::addTU(ASTContext& Ctx) {
|
|
DeclContext *DC = Ctx.getTranslationUnitDecl();
|
|
for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
|
|
I != E; ++I) {
|
|
|
|
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
|
|
if (FD->doesThisDeclarationHaveABody()) {
|
|
// Set caller's ASTContext.
|
|
Entity Ent = Entity::get(FD, Prog);
|
|
CallGraphNode *Node = getOrInsertFunction(Ent);
|
|
CallerCtx[Node] = &Ctx;
|
|
|
|
// If this function has external linkage, anything could call it.
|
|
if (FD->isGlobal())
|
|
ExternalCallingNode->addCallee(idx::ASTLocation(), Node);
|
|
|
|
// Set root node to 'main' function.
|
|
if (FD->getNameAsString() == "main")
|
|
Root = Node;
|
|
|
|
CGBuilder builder(*this, FD, Ent, Node);
|
|
builder.Visit(FD->getBody());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CallGraphNode *CallGraph::getOrInsertFunction(Entity F) {
|
|
CallGraphNode *&Node = FunctionMap[F];
|
|
if (Node)
|
|
return Node;
|
|
|
|
return Node = new CallGraphNode(F);
|
|
}
|
|
|
|
Decl *CallGraph::getDecl(CallGraphNode *Node) {
|
|
// Get the function's context.
|
|
ASTContext *Ctx = CallerCtx[Node];
|
|
|
|
return Node->getDecl(*Ctx);
|
|
}
|
|
|
|
void CallGraph::print(raw_ostream &os) {
|
|
for (iterator I = begin(), E = end(); I != E; ++I) {
|
|
if (I->second->hasCallee()) {
|
|
os << "function: " << I->first.getPrintableName()
|
|
<< " calls:\n";
|
|
for (CallGraphNode::iterator CI = I->second->begin(),
|
|
CE = I->second->end(); CI != CE; ++CI) {
|
|
os << " " << CI->second->getName();
|
|
}
|
|
os << '\n';
|
|
}
|
|
}
|
|
}
|
|
|
|
void CallGraph::dump() {
|
|
print(llvm::errs());
|
|
}
|
|
|
|
void CallGraph::ViewCallGraph() const {
|
|
llvm::ViewGraph(*this, "CallGraph");
|
|
}
|
|
|
|
namespace llvm {
|
|
|
|
template <>
|
|
struct DOTGraphTraits<CallGraph> : public DefaultDOTGraphTraits {
|
|
|
|
DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
|
|
|
|
static std::string getNodeLabel(const CallGraphNode *Node,
|
|
const CallGraph &CG) {
|
|
return Node->getName();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|