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