xref: /openbsd-src/gnu/llvm/clang/lib/Analysis/CallGraph.cpp (revision ec727ea710c91afd8ce4f788c5aaa8482b7b69b2)
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