| //== 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/Analysis/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<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_iterator I=S->child_begin(), E=S->child_end(); I != E;++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); | 
 |  | 
 |     Decl *Parent = ASTLocation::FindImmediateParent(FD, CE); | 
 |      | 
 |     CallerNode->addCallee(ASTLocation(Parent, 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(ASTUnit &AST) { | 
 |   ASTContext &Ctx = AST.getASTContext(); | 
 |   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->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().c_str(); | 
 |       } | 
 |       os << '\n'; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void CallGraph::dump() { | 
 |   print(llvm::errs()); | 
 | } | 
 |  | 
 | void CallGraph::ViewCallGraph() const { | 
 |   llvm::ViewGraph(*this, "CallGraph"); | 
 | } | 
 |  | 
 | namespace llvm { | 
 |  | 
 | template <>  | 
 | struct DOTGraphTraits<CallGraph> : public DefaultDOTGraphTraits { | 
 |  | 
 |   static std::string getNodeLabel(const CallGraphNode *Node,  | 
 |                                   const CallGraph &CG, bool ShortNames) { | 
 |     return Node->getName(); | 
 |      | 
 |   } | 
 |  | 
 | }; | 
 |  | 
 | } |