From: Zhongxing Xu Date: Thu, 16 Jul 2009 00:54:12 +0000 (+0000) Subject: Commit the initial implementation of call graph building. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6bd8fb50acadeeafd923e98cd6a94efeb75693dc;p=clang Commit the initial implementation of call graph building. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@75873 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h new file mode 100644 index 0000000000..bf164c0e72 --- /dev/null +++ b/include/clang/Analysis/CallGraph.h @@ -0,0 +1,84 @@ +//== 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 CallGraphNode classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH +#define LLVM_CLANG_ANALYSIS_CALLGRAPH + +#include "clang/Index/ASTLocation.h" +#include "clang/Index/Entity.h" +#include "clang/Index/Program.h" +#include "clang/Frontend/ASTUnit.h" +#include "llvm/ADT/DenseMap.h" +#include + +namespace clang { + +class CallGraphNode { + idx::Entity *F; + typedef std::pair CallRecord; + std::vector CalledFunctions; + +public: + CallGraphNode(idx::Entity *f) : F(f) {} + + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + iterator begin() { return CalledFunctions.begin(); } + iterator end() { return CalledFunctions.end(); } + const_iterator begin() const { return CalledFunctions.begin(); } + const_iterator end() const { return CalledFunctions.end(); } + + void addCallee(idx::ASTLocation L, CallGraphNode *Node) { + CalledFunctions.push_back(std::make_pair(L, Node)); + } + + const char *getName(ASTContext &Ctx) { return F->getName(Ctx); } +}; + +class CallGraph { + /// Program manages all Entities. + idx::Program Prog; + + typedef llvm::DenseMap FunctionMapTy; + + /// FunctionMap owns all CallGraphNodes. + FunctionMapTy FunctionMap; + + /// CallerCtx maps a caller to its ASTContext. + llvm::DenseMap CallerCtx; + +public: + ~CallGraph(); + + typedef FunctionMapTy::iterator iterator; + typedef FunctionMapTy::const_iterator const_iterator; + + iterator begin() { return FunctionMap.begin(); } + iterator end() { return FunctionMap.end(); } + const_iterator begin() const { return FunctionMap.begin(); } + const_iterator end() const { return FunctionMap.end(); } + + void addTU(ASTUnit &AST); + + idx::Program &getProgram() { return Prog; } + + CallGraphNode *getOrInsertFunction(idx::Entity *F); + + void print(llvm::raw_ostream &os); + void dump(); +}; + +} + +#endif diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp new file mode 100644 index 0000000000..a296f60553 --- /dev/null +++ b/lib/Analysis/CallGraph.cpp @@ -0,0 +1,121 @@ +//== 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" + +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 VisitCompoundStmt(CompoundStmt *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) { + Expr *Callee = CE->getCallee(); + + if (CastExpr *CE = dyn_cast(Callee)) + Callee = CE->getSubExpr(); + + if (DeclRefExpr *DRE = dyn_cast(Callee)) { + Decl *D = DRE->getDecl(); + if (FunctionDecl *CalleeDecl = dyn_cast(D)) { + + Entity *Ent = Entity::get(CalleeDecl, G.getProgram()); + + CallGraphNode *CalleeNode = G.getOrInsertFunction(Ent); + + CallerNode->addCallee(ASTLocation(FD, CE), CalleeNode); + } + } +} + +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(*I)) { + if (FD->isThisDeclarationADefinition()) { + // Set caller's ASTContext. + Entity *Ent = Entity::get(FD, Prog); + CallGraphNode *Node = getOrInsertFunction(Ent); + CallerCtx[Node] = &Ctx; + + 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); +} + +void CallGraph::print(llvm::raw_ostream &os) { + for (iterator I = begin(), E = end(); I != E; ++I) { + ASTContext &Ctx = *CallerCtx[I->second]; + os << "function: " << I->first->getName(Ctx) << " calls:\n"; + for (CallGraphNode::iterator CI = I->second->begin(), CE = I->second->end(); + CI != CE; ++CI) { + os << " " << CI->second->getName(Ctx); + } + os << '\n'; + } +} + +void CallGraph::dump() { + print(llvm::errs()); +}