Clang Project

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