1e5dd7070Spatrick //===- CallGraph.cpp - AST-based Call graph -------------------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file defines the AST-based CallGraph.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #include "clang/Analysis/CallGraph.h"
14e5dd7070Spatrick #include "clang/AST/Decl.h"
15e5dd7070Spatrick #include "clang/AST/DeclBase.h"
16e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
17e5dd7070Spatrick #include "clang/AST/Expr.h"
18e5dd7070Spatrick #include "clang/AST/ExprObjC.h"
19e5dd7070Spatrick #include "clang/AST/Stmt.h"
20e5dd7070Spatrick #include "clang/AST/StmtVisitor.h"
21e5dd7070Spatrick #include "clang/Basic/IdentifierTable.h"
22e5dd7070Spatrick #include "clang/Basic/LLVM.h"
23e5dd7070Spatrick #include "llvm/ADT/PostOrderIterator.h"
24e5dd7070Spatrick #include "llvm/ADT/STLExtras.h"
25e5dd7070Spatrick #include "llvm/ADT/Statistic.h"
26e5dd7070Spatrick #include "llvm/Support/Casting.h"
27e5dd7070Spatrick #include "llvm/Support/Compiler.h"
28e5dd7070Spatrick #include "llvm/Support/DOTGraphTraits.h"
29e5dd7070Spatrick #include "llvm/Support/GraphWriter.h"
30e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
31e5dd7070Spatrick #include <cassert>
32e5dd7070Spatrick #include <memory>
33e5dd7070Spatrick #include <string>
34e5dd7070Spatrick
35e5dd7070Spatrick using namespace clang;
36e5dd7070Spatrick
37e5dd7070Spatrick #define DEBUG_TYPE "CallGraph"
38e5dd7070Spatrick
39e5dd7070Spatrick STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges");
40e5dd7070Spatrick STATISTIC(NumBlockCallEdges, "Number of block call edges");
41e5dd7070Spatrick
42e5dd7070Spatrick namespace {
43e5dd7070Spatrick
44e5dd7070Spatrick /// A helper class, which walks the AST and locates all the call sites in the
45e5dd7070Spatrick /// given function body.
46e5dd7070Spatrick class CGBuilder : public StmtVisitor<CGBuilder> {
47e5dd7070Spatrick CallGraph *G;
48e5dd7070Spatrick CallGraphNode *CallerNode;
49e5dd7070Spatrick
50e5dd7070Spatrick public:
CGBuilder(CallGraph * g,CallGraphNode * N)51e5dd7070Spatrick CGBuilder(CallGraph *g, CallGraphNode *N) : G(g), CallerNode(N) {}
52e5dd7070Spatrick
VisitStmt(Stmt * S)53e5dd7070Spatrick void VisitStmt(Stmt *S) { VisitChildren(S); }
54e5dd7070Spatrick
getDeclFromCall(CallExpr * CE)55e5dd7070Spatrick Decl *getDeclFromCall(CallExpr *CE) {
56e5dd7070Spatrick if (FunctionDecl *CalleeDecl = CE->getDirectCallee())
57e5dd7070Spatrick return CalleeDecl;
58e5dd7070Spatrick
59e5dd7070Spatrick // Simple detection of a call through a block.
60e5dd7070Spatrick Expr *CEE = CE->getCallee()->IgnoreParenImpCasts();
61e5dd7070Spatrick if (BlockExpr *Block = dyn_cast<BlockExpr>(CEE)) {
62e5dd7070Spatrick NumBlockCallEdges++;
63e5dd7070Spatrick return Block->getBlockDecl();
64e5dd7070Spatrick }
65e5dd7070Spatrick
66e5dd7070Spatrick return nullptr;
67e5dd7070Spatrick }
68e5dd7070Spatrick
addCalledDecl(Decl * D,Expr * CallExpr)69*ec727ea7Spatrick void addCalledDecl(Decl *D, Expr *CallExpr) {
70*ec727ea7Spatrick if (G->includeCalleeInGraph(D)) {
71e5dd7070Spatrick CallGraphNode *CalleeNode = G->getOrInsertNode(D);
72*ec727ea7Spatrick CallerNode->addCallee({CalleeNode, CallExpr});
73e5dd7070Spatrick }
74e5dd7070Spatrick }
75e5dd7070Spatrick
VisitCallExpr(CallExpr * CE)76e5dd7070Spatrick void VisitCallExpr(CallExpr *CE) {
77e5dd7070Spatrick if (Decl *D = getDeclFromCall(CE))
78*ec727ea7Spatrick addCalledDecl(D, CE);
79e5dd7070Spatrick VisitChildren(CE);
80e5dd7070Spatrick }
81e5dd7070Spatrick
VisitLambdaExpr(LambdaExpr * LE)82e5dd7070Spatrick void VisitLambdaExpr(LambdaExpr *LE) {
83e5dd7070Spatrick if (FunctionTemplateDecl *FTD = LE->getDependentCallOperator())
84e5dd7070Spatrick for (FunctionDecl *FD : FTD->specializations())
85e5dd7070Spatrick G->VisitFunctionDecl(FD);
86e5dd7070Spatrick else if (CXXMethodDecl *MD = LE->getCallOperator())
87e5dd7070Spatrick G->VisitFunctionDecl(MD);
88e5dd7070Spatrick }
89e5dd7070Spatrick
VisitCXXNewExpr(CXXNewExpr * E)90e5dd7070Spatrick void VisitCXXNewExpr(CXXNewExpr *E) {
91e5dd7070Spatrick if (FunctionDecl *FD = E->getOperatorNew())
92*ec727ea7Spatrick addCalledDecl(FD, E);
93e5dd7070Spatrick VisitChildren(E);
94e5dd7070Spatrick }
95e5dd7070Spatrick
VisitCXXConstructExpr(CXXConstructExpr * E)96e5dd7070Spatrick void VisitCXXConstructExpr(CXXConstructExpr *E) {
97e5dd7070Spatrick CXXConstructorDecl *Ctor = E->getConstructor();
98e5dd7070Spatrick if (FunctionDecl *Def = Ctor->getDefinition())
99*ec727ea7Spatrick addCalledDecl(Def, E);
100e5dd7070Spatrick VisitChildren(E);
101e5dd7070Spatrick }
102e5dd7070Spatrick
103e5dd7070Spatrick // Include the evaluation of the default argument.
VisitCXXDefaultArgExpr(CXXDefaultArgExpr * E)104e5dd7070Spatrick void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
105e5dd7070Spatrick Visit(E->getExpr());
106e5dd7070Spatrick }
107e5dd7070Spatrick
108e5dd7070Spatrick // Include the evaluation of the default initializers in a class.
VisitCXXDefaultInitExpr(CXXDefaultInitExpr * E)109e5dd7070Spatrick void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
110e5dd7070Spatrick Visit(E->getExpr());
111e5dd7070Spatrick }
112e5dd7070Spatrick
113e5dd7070Spatrick // Adds may-call edges for the ObjC message sends.
VisitObjCMessageExpr(ObjCMessageExpr * ME)114e5dd7070Spatrick void VisitObjCMessageExpr(ObjCMessageExpr *ME) {
115e5dd7070Spatrick if (ObjCInterfaceDecl *IDecl = ME->getReceiverInterface()) {
116e5dd7070Spatrick Selector Sel = ME->getSelector();
117e5dd7070Spatrick
118e5dd7070Spatrick // Find the callee definition within the same translation unit.
119e5dd7070Spatrick Decl *D = nullptr;
120e5dd7070Spatrick if (ME->isInstanceMessage())
121e5dd7070Spatrick D = IDecl->lookupPrivateMethod(Sel);
122e5dd7070Spatrick else
123e5dd7070Spatrick D = IDecl->lookupPrivateClassMethod(Sel);
124e5dd7070Spatrick if (D) {
125*ec727ea7Spatrick addCalledDecl(D, ME);
126e5dd7070Spatrick NumObjCCallEdges++;
127e5dd7070Spatrick }
128e5dd7070Spatrick }
129e5dd7070Spatrick }
130e5dd7070Spatrick
VisitChildren(Stmt * S)131e5dd7070Spatrick void VisitChildren(Stmt *S) {
132e5dd7070Spatrick for (Stmt *SubStmt : S->children())
133e5dd7070Spatrick if (SubStmt)
134e5dd7070Spatrick this->Visit(SubStmt);
135e5dd7070Spatrick }
136e5dd7070Spatrick };
137e5dd7070Spatrick
138e5dd7070Spatrick } // namespace
139e5dd7070Spatrick
addNodesForBlocks(DeclContext * D)140e5dd7070Spatrick void CallGraph::addNodesForBlocks(DeclContext *D) {
141e5dd7070Spatrick if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
142e5dd7070Spatrick addNodeForDecl(BD, true);
143e5dd7070Spatrick
144e5dd7070Spatrick for (auto *I : D->decls())
145e5dd7070Spatrick if (auto *DC = dyn_cast<DeclContext>(I))
146e5dd7070Spatrick addNodesForBlocks(DC);
147e5dd7070Spatrick }
148e5dd7070Spatrick
CallGraph()149e5dd7070Spatrick CallGraph::CallGraph() {
150e5dd7070Spatrick Root = getOrInsertNode(nullptr);
151e5dd7070Spatrick }
152e5dd7070Spatrick
153e5dd7070Spatrick CallGraph::~CallGraph() = default;
154e5dd7070Spatrick
includeInGraph(const Decl * D)155e5dd7070Spatrick bool CallGraph::includeInGraph(const Decl *D) {
156e5dd7070Spatrick assert(D);
157e5dd7070Spatrick if (!D->hasBody())
158e5dd7070Spatrick return false;
159e5dd7070Spatrick
160*ec727ea7Spatrick return includeCalleeInGraph(D);
161*ec727ea7Spatrick }
162*ec727ea7Spatrick
includeCalleeInGraph(const Decl * D)163*ec727ea7Spatrick bool CallGraph::includeCalleeInGraph(const Decl *D) {
164e5dd7070Spatrick if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
165e5dd7070Spatrick // We skip function template definitions, as their semantics is
166e5dd7070Spatrick // only determined when they are instantiated.
167e5dd7070Spatrick if (FD->isDependentContext())
168e5dd7070Spatrick return false;
169e5dd7070Spatrick
170e5dd7070Spatrick IdentifierInfo *II = FD->getIdentifier();
171e5dd7070Spatrick if (II && II->getName().startswith("__inline"))
172e5dd7070Spatrick return false;
173e5dd7070Spatrick }
174e5dd7070Spatrick
175e5dd7070Spatrick return true;
176e5dd7070Spatrick }
177e5dd7070Spatrick
addNodeForDecl(Decl * D,bool IsGlobal)178e5dd7070Spatrick void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
179e5dd7070Spatrick assert(D);
180e5dd7070Spatrick
181e5dd7070Spatrick // Allocate a new node, mark it as root, and process its calls.
182e5dd7070Spatrick CallGraphNode *Node = getOrInsertNode(D);
183e5dd7070Spatrick
184e5dd7070Spatrick // Process all the calls by this function as well.
185e5dd7070Spatrick CGBuilder builder(this, Node);
186e5dd7070Spatrick if (Stmt *Body = D->getBody())
187e5dd7070Spatrick builder.Visit(Body);
188e5dd7070Spatrick
189e5dd7070Spatrick // Include C++ constructor member initializers.
190e5dd7070Spatrick if (auto constructor = dyn_cast<CXXConstructorDecl>(D)) {
191e5dd7070Spatrick for (CXXCtorInitializer *init : constructor->inits()) {
192e5dd7070Spatrick builder.Visit(init->getInit());
193e5dd7070Spatrick }
194e5dd7070Spatrick }
195e5dd7070Spatrick }
196e5dd7070Spatrick
getNode(const Decl * F) const197e5dd7070Spatrick CallGraphNode *CallGraph::getNode(const Decl *F) const {
198e5dd7070Spatrick FunctionMapTy::const_iterator I = FunctionMap.find(F);
199e5dd7070Spatrick if (I == FunctionMap.end()) return nullptr;
200e5dd7070Spatrick return I->second.get();
201e5dd7070Spatrick }
202e5dd7070Spatrick
getOrInsertNode(Decl * F)203e5dd7070Spatrick CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
204e5dd7070Spatrick if (F && !isa<ObjCMethodDecl>(F))
205e5dd7070Spatrick F = F->getCanonicalDecl();
206e5dd7070Spatrick
207e5dd7070Spatrick std::unique_ptr<CallGraphNode> &Node = FunctionMap[F];
208e5dd7070Spatrick if (Node)
209e5dd7070Spatrick return Node.get();
210e5dd7070Spatrick
211e5dd7070Spatrick Node = std::make_unique<CallGraphNode>(F);
212e5dd7070Spatrick // Make Root node a parent of all functions to make sure all are reachable.
213e5dd7070Spatrick if (F)
214*ec727ea7Spatrick Root->addCallee({Node.get(), /*Call=*/nullptr});
215e5dd7070Spatrick return Node.get();
216e5dd7070Spatrick }
217e5dd7070Spatrick
print(raw_ostream & OS) const218e5dd7070Spatrick void CallGraph::print(raw_ostream &OS) const {
219e5dd7070Spatrick OS << " --- Call graph Dump --- \n";
220e5dd7070Spatrick
221e5dd7070Spatrick // We are going to print the graph in reverse post order, partially, to make
222e5dd7070Spatrick // sure the output is deterministic.
223e5dd7070Spatrick llvm::ReversePostOrderTraversal<const CallGraph *> RPOT(this);
224e5dd7070Spatrick for (llvm::ReversePostOrderTraversal<const CallGraph *>::rpo_iterator
225e5dd7070Spatrick I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
226e5dd7070Spatrick const CallGraphNode *N = *I;
227e5dd7070Spatrick
228e5dd7070Spatrick OS << " Function: ";
229e5dd7070Spatrick if (N == Root)
230e5dd7070Spatrick OS << "< root >";
231e5dd7070Spatrick else
232e5dd7070Spatrick N->print(OS);
233e5dd7070Spatrick
234e5dd7070Spatrick OS << " calls: ";
235e5dd7070Spatrick for (CallGraphNode::const_iterator CI = N->begin(),
236e5dd7070Spatrick CE = N->end(); CI != CE; ++CI) {
237*ec727ea7Spatrick assert(CI->Callee != Root && "No one can call the root node.");
238*ec727ea7Spatrick CI->Callee->print(OS);
239e5dd7070Spatrick OS << " ";
240e5dd7070Spatrick }
241e5dd7070Spatrick OS << '\n';
242e5dd7070Spatrick }
243e5dd7070Spatrick OS.flush();
244e5dd7070Spatrick }
245e5dd7070Spatrick
dump() const246e5dd7070Spatrick LLVM_DUMP_METHOD void CallGraph::dump() const {
247e5dd7070Spatrick print(llvm::errs());
248e5dd7070Spatrick }
249e5dd7070Spatrick
viewGraph() const250e5dd7070Spatrick void CallGraph::viewGraph() const {
251e5dd7070Spatrick llvm::ViewGraph(this, "CallGraph");
252e5dd7070Spatrick }
253e5dd7070Spatrick
print(raw_ostream & os) const254e5dd7070Spatrick void CallGraphNode::print(raw_ostream &os) const {
255e5dd7070Spatrick if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(FD))
256e5dd7070Spatrick return ND->printQualifiedName(os);
257e5dd7070Spatrick os << "< >";
258e5dd7070Spatrick }
259e5dd7070Spatrick
dump() const260e5dd7070Spatrick LLVM_DUMP_METHOD void CallGraphNode::dump() const {
261e5dd7070Spatrick print(llvm::errs());
262e5dd7070Spatrick }
263e5dd7070Spatrick
264e5dd7070Spatrick namespace llvm {
265e5dd7070Spatrick
266e5dd7070Spatrick template <>
267e5dd7070Spatrick struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits {
DOTGraphTraitsllvm::DOTGraphTraits268e5dd7070Spatrick DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
269e5dd7070Spatrick
getNodeLabelllvm::DOTGraphTraits270e5dd7070Spatrick static std::string getNodeLabel(const CallGraphNode *Node,
271e5dd7070Spatrick const CallGraph *CG) {
272e5dd7070Spatrick if (CG->getRoot() == Node) {
273e5dd7070Spatrick return "< root >";
274e5dd7070Spatrick }
275e5dd7070Spatrick if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Node->getDecl()))
276e5dd7070Spatrick return ND->getNameAsString();
277e5dd7070Spatrick else
278e5dd7070Spatrick return "< >";
279e5dd7070Spatrick }
280e5dd7070Spatrick };
281e5dd7070Spatrick
282e5dd7070Spatrick } // namespace llvm
283