//== CallGraph.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/CallGraph.h" #include "clang/AST/ASTContext.h" #include "clang/AST/StmtVisitor.h" #include "llvm/Support/GraphWriter.h" using namespace clang; using namespace idx; namespace { class CGBuilder : public StmtVisitor { 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_iterator I=S->child_begin(), E=S->child_end(); I != E;++I) if (*I) static_cast(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() : 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(*I)) { if (FD->isThisDeclarationADefinition()) { // 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(llvm::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 : public DefaultDOTGraphTraits { DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} static std::string getNodeLabel(const CallGraphNode *Node, const CallGraph &CG) { return Node->getName(); } }; }