blob: a296f60553244c7c10d1dfd4fa7933615fd88c82 [file] [log] [blame]
Zhongxing Xua62ad242009-07-16 00:54:12 +00001//== CallGraph.cpp - Call graph building ------------------------*- C++ -*--==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defined the CallGraph and CGBuilder classes.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Analysis/CallGraph.h"
15
16#include "clang/AST/ASTContext.h"
17#include "clang/AST/StmtVisitor.h"
18
19using namespace clang;
20using namespace idx;
21
22namespace {
23class CGBuilder : public StmtVisitor<CGBuilder> {
24
25 CallGraph &G;
26 FunctionDecl *FD;
27
28 Entity *CallerEnt;
29
30 CallGraphNode *CallerNode;
31
32public:
33 CGBuilder(CallGraph &g, FunctionDecl *fd, Entity *E, CallGraphNode *N)
34 : G(g), FD(fd), CallerEnt(E), CallerNode(N) {}
35
36 void VisitCompoundStmt(CompoundStmt *S) {
37 VisitChildren(S);
38 }
39
40 void VisitCallExpr(CallExpr *CE);
41
42 void VisitChildren(Stmt *S) {
43 for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I)
44 if (*I)
45 static_cast<CGBuilder*>(this)->Visit(*I);
46 }
47};
48}
49
50void CGBuilder::VisitCallExpr(CallExpr *CE) {
51 Expr *Callee = CE->getCallee();
52
53 if (CastExpr *CE = dyn_cast<CastExpr>(Callee))
54 Callee = CE->getSubExpr();
55
56 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee)) {
57 Decl *D = DRE->getDecl();
58 if (FunctionDecl *CalleeDecl = dyn_cast<FunctionDecl>(D)) {
59
60 Entity *Ent = Entity::get(CalleeDecl, G.getProgram());
61
62 CallGraphNode *CalleeNode = G.getOrInsertFunction(Ent);
63
64 CallerNode->addCallee(ASTLocation(FD, CE), CalleeNode);
65 }
66 }
67}
68
69CallGraph::~CallGraph() {
70 if (!FunctionMap.empty()) {
71 for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
72 I != E; ++I)
73 delete I->second;
74 FunctionMap.clear();
75 }
76}
77
78void CallGraph::addTU(ASTUnit &AST) {
79 ASTContext &Ctx = AST.getASTContext();
80 DeclContext *DC = Ctx.getTranslationUnitDecl();
81
82 for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
83 I != E; ++I) {
84
85 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
86 if (FD->isThisDeclarationADefinition()) {
87 // Set caller's ASTContext.
88 Entity *Ent = Entity::get(FD, Prog);
89 CallGraphNode *Node = getOrInsertFunction(Ent);
90 CallerCtx[Node] = &Ctx;
91
92 CGBuilder builder(*this, FD, Ent, Node);
93 builder.Visit(FD->getBody());
94 }
95 }
96 }
97}
98
99CallGraphNode *CallGraph::getOrInsertFunction(Entity *F) {
100 CallGraphNode *&Node = FunctionMap[F];
101 if (Node)
102 return Node;
103
104 return Node = new CallGraphNode(F);
105}
106
107void CallGraph::print(llvm::raw_ostream &os) {
108 for (iterator I = begin(), E = end(); I != E; ++I) {
109 ASTContext &Ctx = *CallerCtx[I->second];
110 os << "function: " << I->first->getName(Ctx) << " calls:\n";
111 for (CallGraphNode::iterator CI = I->second->begin(), CE = I->second->end();
112 CI != CE; ++CI) {
113 os << " " << CI->second->getName(Ctx);
114 }
115 os << '\n';
116 }
117}
118
119void CallGraph::dump() {
120 print(llvm::errs());
121}