blob: 12a6fe650ffb5e1a60529cb231989ad462e8829a [file] [log] [blame]
Anna Zaks196b8cf2012-03-08 00:42:23 +00001//== CallGraph.cpp - AST-based Call graph ----------------------*- 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 defines the AST-based CallGraph.
11//
12//===----------------------------------------------------------------------===//
13#include "clang/Analysis/CallGraph.h"
Anna Zaks196b8cf2012-03-08 00:42:23 +000014#include "clang/AST/ASTContext.h"
15#include "clang/AST/Decl.h"
16#include "clang/AST/StmtVisitor.h"
Anna Zaks196b8cf2012-03-08 00:42:23 +000017#include "llvm/Support/GraphWriter.h"
18
19using namespace clang;
20
Anna Zaks6a860822012-04-12 22:36:48 +000021namespace {
22/// A helper class, which walks the AST and locates all the call sites in the
23/// given function body.
24class CGBuilder : public StmtVisitor<CGBuilder> {
25 CallGraph *G;
Anna Zaks6a860822012-04-12 22:36:48 +000026 CallGraphNode *CallerNode;
27
28public:
Benjamin Kramerfacde172012-06-06 17:32:50 +000029 CGBuilder(CallGraph *g, CallGraphNode *N)
30 : G(g), CallerNode(N) {}
Anna Zaks6a860822012-04-12 22:36:48 +000031
32 void VisitStmt(Stmt *S) { VisitChildren(S); }
33
34 void VisitCallExpr(CallExpr *CE) {
35 // TODO: We need to handle ObjC method calls as well.
36 if (FunctionDecl *CalleeDecl = CE->getDirectCallee())
37 if (G->includeInGraph(CalleeDecl)) {
38 CallGraphNode *CalleeNode = G->getOrInsertNode(CalleeDecl);
39 CallerNode->addCallee(CalleeNode, G);
40 }
41 }
42
43 void VisitChildren(Stmt *S) {
44 for (Stmt::child_range I = S->children(); I; ++I)
45 if (*I)
46 static_cast<CGBuilder*>(this)->Visit(*I);
47 }
48};
49
50} // end anonymous namespace
51
52CallGraph::CallGraph() {
53 Root = getOrInsertNode(0);
54}
55
56CallGraph::~CallGraph() {
57 if (!FunctionMap.empty()) {
58 for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
59 I != E; ++I)
60 delete I->second;
61 FunctionMap.clear();
62 }
63}
64
65bool CallGraph::includeInGraph(const Decl *D) {
Anna Zaks196b8cf2012-03-08 00:42:23 +000066 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
67 // We skip function template definitions, as their semantics is
68 // only determined when they are instantiated.
69 if (!FD->isThisDeclarationADefinition() ||
70 FD->isDependentContext())
71 return false;
72
73 IdentifierInfo *II = FD->getIdentifier();
74 if (II && II->getName().startswith("__inline"))
75 return false;
76 }
77
78 if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
79 if (!ID->isThisDeclarationADefinition())
80 return false;
81 }
82
83 return true;
84}
85
Anna Zaks6a860822012-04-12 22:36:48 +000086void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
Anna Zaksd2776612012-03-08 23:16:26 +000087 assert(D);
Anna Zaks196b8cf2012-03-08 00:42:23 +000088
Anna Zaks6a860822012-04-12 22:36:48 +000089 // Do nothing if the node already exists.
90 if (FunctionMap.find(D) != FunctionMap.end())
91 return;
92
93 // Allocate a new node, mark it as root, and process it's calls.
94 CallGraphNode *Node = getOrInsertNode(D);
Anna Zaks196b8cf2012-03-08 00:42:23 +000095 if (IsGlobal)
96 Root->addCallee(Node, this);
97
98 // Process all the calls by this function as well.
Benjamin Kramerfacde172012-06-06 17:32:50 +000099 CGBuilder builder(this, Node);
Ted Kremenekbb3d20f2012-04-05 04:03:23 +0000100 if (Stmt *Body = D->getBody())
101 builder.Visit(Body);
Anna Zaks196b8cf2012-03-08 00:42:23 +0000102}
103
Anna Zaksa5d531f2012-03-09 21:13:53 +0000104CallGraphNode *CallGraph::getNode(const Decl *F) const {
Matt Beaumont-Gayd53e8772012-03-14 20:21:25 +0000105 FunctionMapTy::const_iterator I = FunctionMap.find(F);
106 if (I == FunctionMap.end()) return 0;
107 return I->second;
Anna Zaksa5d531f2012-03-09 21:13:53 +0000108}
109
Anna Zaks6a860822012-04-12 22:36:48 +0000110CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
Anna Zaks196b8cf2012-03-08 00:42:23 +0000111 CallGraphNode *&Node = FunctionMap[F];
112 if (Node)
113 return Node;
114
115 Node = new CallGraphNode(F);
Anna Zaksd2776612012-03-08 23:16:26 +0000116 // If not root, add to the parentless list.
117 if (F != 0)
118 ParentlessNodes.insert(Node);
Anna Zaks196b8cf2012-03-08 00:42:23 +0000119 return Node;
120}
121
122void CallGraph::print(raw_ostream &OS) const {
123 OS << " --- Call graph Dump --- \n";
124 for (const_iterator I = begin(), E = end(); I != E; ++I) {
125 OS << " Function: ";
126 if (I->second == Root)
127 OS << "< root >";
128 else
129 I->second->print(OS);
130 OS << " calls: ";
131 for (CallGraphNode::iterator CI = I->second->begin(),
132 CE = I->second->end(); CI != CE; ++CI) {
133 assert(*CI != Root && "No one can call the root node.");
134 (*CI)->print(OS);
135 OS << " ";
136 }
137 OS << '\n';
138 }
139 OS.flush();
140}
141
142void CallGraph::dump() const {
143 print(llvm::errs());
144}
145
146void CallGraph::viewGraph() const {
147 llvm::ViewGraph(this, "CallGraph");
148}
149
150StringRef CallGraphNode::getName() const {
151 if (const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(FD))
152 if (const IdentifierInfo *II = D->getIdentifier())
153 return II->getName();
154 return "< >";
155}
156
157void CallGraphNode::print(raw_ostream &os) const {
158 os << getName();
159}
160
161void CallGraphNode::dump() const {
162 print(llvm::errs());
163}
164
165namespace llvm {
166
167template <>
168struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits {
169
170 DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
171
172 static std::string getNodeLabel(const CallGraphNode *Node,
173 const CallGraph *CG) {
174 if (CG->getRoot() == Node) {
175 return "< root >";
176 }
177 return Node->getName();
178 }
179
180};
181}