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