10b57cec5SDimitry Andric //===- CallGraph.cpp - AST-based Call graph -------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines the AST-based CallGraph.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "clang/Analysis/CallGraph.h"
140b57cec5SDimitry Andric #include "clang/AST/Decl.h"
150b57cec5SDimitry Andric #include "clang/AST/DeclBase.h"
160b57cec5SDimitry Andric #include "clang/AST/DeclObjC.h"
170b57cec5SDimitry Andric #include "clang/AST/Expr.h"
180b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h"
190b57cec5SDimitry Andric #include "clang/AST/Stmt.h"
200b57cec5SDimitry Andric #include "clang/AST/StmtVisitor.h"
210b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h"
220b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
230b57cec5SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
240b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
250b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
260b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
270b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
280b57cec5SDimitry Andric #include "llvm/Support/DOTGraphTraits.h"
290b57cec5SDimitry Andric #include "llvm/Support/GraphWriter.h"
300b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
310b57cec5SDimitry Andric #include <cassert>
320b57cec5SDimitry Andric #include <memory>
330b57cec5SDimitry Andric #include <string>
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric using namespace clang;
360b57cec5SDimitry Andric
370b57cec5SDimitry Andric #define DEBUG_TYPE "CallGraph"
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges");
400b57cec5SDimitry Andric STATISTIC(NumBlockCallEdges, "Number of block call edges");
410b57cec5SDimitry Andric
420b57cec5SDimitry Andric namespace {
430b57cec5SDimitry Andric
440b57cec5SDimitry Andric /// A helper class, which walks the AST and locates all the call sites in the
450b57cec5SDimitry Andric /// given function body.
460b57cec5SDimitry Andric class CGBuilder : public StmtVisitor<CGBuilder> {
470b57cec5SDimitry Andric CallGraph *G;
480b57cec5SDimitry Andric CallGraphNode *CallerNode;
490b57cec5SDimitry Andric
500b57cec5SDimitry Andric public:
CGBuilder(CallGraph * g,CallGraphNode * N)510b57cec5SDimitry Andric CGBuilder(CallGraph *g, CallGraphNode *N) : G(g), CallerNode(N) {}
520b57cec5SDimitry Andric
VisitStmt(Stmt * S)530b57cec5SDimitry Andric void VisitStmt(Stmt *S) { VisitChildren(S); }
540b57cec5SDimitry Andric
getDeclFromCall(CallExpr * CE)550b57cec5SDimitry Andric Decl *getDeclFromCall(CallExpr *CE) {
560b57cec5SDimitry Andric if (FunctionDecl *CalleeDecl = CE->getDirectCallee())
570b57cec5SDimitry Andric return CalleeDecl;
580b57cec5SDimitry Andric
590b57cec5SDimitry Andric // Simple detection of a call through a block.
600b57cec5SDimitry Andric Expr *CEE = CE->getCallee()->IgnoreParenImpCasts();
610b57cec5SDimitry Andric if (BlockExpr *Block = dyn_cast<BlockExpr>(CEE)) {
620b57cec5SDimitry Andric NumBlockCallEdges++;
630b57cec5SDimitry Andric return Block->getBlockDecl();
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric
660b57cec5SDimitry Andric return nullptr;
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric
addCalledDecl(Decl * D,Expr * CallExpr)695ffd83dbSDimitry Andric void addCalledDecl(Decl *D, Expr *CallExpr) {
705ffd83dbSDimitry Andric if (G->includeCalleeInGraph(D)) {
710b57cec5SDimitry Andric CallGraphNode *CalleeNode = G->getOrInsertNode(D);
725ffd83dbSDimitry Andric CallerNode->addCallee({CalleeNode, CallExpr});
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric
VisitCallExpr(CallExpr * CE)760b57cec5SDimitry Andric void VisitCallExpr(CallExpr *CE) {
770b57cec5SDimitry Andric if (Decl *D = getDeclFromCall(CE))
785ffd83dbSDimitry Andric addCalledDecl(D, CE);
790b57cec5SDimitry Andric VisitChildren(CE);
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric
VisitLambdaExpr(LambdaExpr * LE)82a7dea167SDimitry Andric void VisitLambdaExpr(LambdaExpr *LE) {
83a7dea167SDimitry Andric if (FunctionTemplateDecl *FTD = LE->getDependentCallOperator())
84a7dea167SDimitry Andric for (FunctionDecl *FD : FTD->specializations())
85a7dea167SDimitry Andric G->VisitFunctionDecl(FD);
86a7dea167SDimitry Andric else if (CXXMethodDecl *MD = LE->getCallOperator())
87a7dea167SDimitry Andric G->VisitFunctionDecl(MD);
88a7dea167SDimitry Andric }
89a7dea167SDimitry Andric
VisitCXXNewExpr(CXXNewExpr * E)90a7dea167SDimitry Andric void VisitCXXNewExpr(CXXNewExpr *E) {
91a7dea167SDimitry Andric if (FunctionDecl *FD = E->getOperatorNew())
925ffd83dbSDimitry Andric addCalledDecl(FD, E);
93a7dea167SDimitry Andric VisitChildren(E);
94a7dea167SDimitry Andric }
95a7dea167SDimitry Andric
VisitCXXConstructExpr(CXXConstructExpr * E)96a7dea167SDimitry Andric void VisitCXXConstructExpr(CXXConstructExpr *E) {
97a7dea167SDimitry Andric CXXConstructorDecl *Ctor = E->getConstructor();
98a7dea167SDimitry Andric if (FunctionDecl *Def = Ctor->getDefinition())
995ffd83dbSDimitry Andric addCalledDecl(Def, E);
100a7dea167SDimitry Andric VisitChildren(E);
101a7dea167SDimitry Andric }
102a7dea167SDimitry Andric
103a7dea167SDimitry Andric // Include the evaluation of the default argument.
VisitCXXDefaultArgExpr(CXXDefaultArgExpr * E)104a7dea167SDimitry Andric void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
105a7dea167SDimitry Andric Visit(E->getExpr());
106a7dea167SDimitry Andric }
107a7dea167SDimitry Andric
108a7dea167SDimitry Andric // Include the evaluation of the default initializers in a class.
VisitCXXDefaultInitExpr(CXXDefaultInitExpr * E)109a7dea167SDimitry Andric void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
110a7dea167SDimitry Andric Visit(E->getExpr());
111a7dea167SDimitry Andric }
112a7dea167SDimitry Andric
1130b57cec5SDimitry Andric // Adds may-call edges for the ObjC message sends.
VisitObjCMessageExpr(ObjCMessageExpr * ME)1140b57cec5SDimitry Andric void VisitObjCMessageExpr(ObjCMessageExpr *ME) {
1150b57cec5SDimitry Andric if (ObjCInterfaceDecl *IDecl = ME->getReceiverInterface()) {
1160b57cec5SDimitry Andric Selector Sel = ME->getSelector();
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric // Find the callee definition within the same translation unit.
1190b57cec5SDimitry Andric Decl *D = nullptr;
1200b57cec5SDimitry Andric if (ME->isInstanceMessage())
1210b57cec5SDimitry Andric D = IDecl->lookupPrivateMethod(Sel);
1220b57cec5SDimitry Andric else
1230b57cec5SDimitry Andric D = IDecl->lookupPrivateClassMethod(Sel);
1240b57cec5SDimitry Andric if (D) {
1255ffd83dbSDimitry Andric addCalledDecl(D, ME);
1260b57cec5SDimitry Andric NumObjCCallEdges++;
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric
VisitChildren(Stmt * S)1310b57cec5SDimitry Andric void VisitChildren(Stmt *S) {
1320b57cec5SDimitry Andric for (Stmt *SubStmt : S->children())
1330b57cec5SDimitry Andric if (SubStmt)
1340b57cec5SDimitry Andric this->Visit(SubStmt);
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric };
1370b57cec5SDimitry Andric
1380b57cec5SDimitry Andric } // namespace
1390b57cec5SDimitry Andric
addNodesForBlocks(DeclContext * D)1400b57cec5SDimitry Andric void CallGraph::addNodesForBlocks(DeclContext *D) {
1410b57cec5SDimitry Andric if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
1420b57cec5SDimitry Andric addNodeForDecl(BD, true);
1430b57cec5SDimitry Andric
1440b57cec5SDimitry Andric for (auto *I : D->decls())
1450b57cec5SDimitry Andric if (auto *DC = dyn_cast<DeclContext>(I))
1460b57cec5SDimitry Andric addNodesForBlocks(DC);
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric
CallGraph()1490b57cec5SDimitry Andric CallGraph::CallGraph() {
1500b57cec5SDimitry Andric Root = getOrInsertNode(nullptr);
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric
1530b57cec5SDimitry Andric CallGraph::~CallGraph() = default;
1540b57cec5SDimitry Andric
includeInGraph(const Decl * D)1550b57cec5SDimitry Andric bool CallGraph::includeInGraph(const Decl *D) {
1560b57cec5SDimitry Andric assert(D);
1570b57cec5SDimitry Andric if (!D->hasBody())
1580b57cec5SDimitry Andric return false;
1590b57cec5SDimitry Andric
1605ffd83dbSDimitry Andric return includeCalleeInGraph(D);
1615ffd83dbSDimitry Andric }
1625ffd83dbSDimitry Andric
includeCalleeInGraph(const Decl * D)1635ffd83dbSDimitry Andric bool CallGraph::includeCalleeInGraph(const Decl *D) {
1640b57cec5SDimitry Andric if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
1650b57cec5SDimitry Andric // We skip function template definitions, as their semantics is
1660b57cec5SDimitry Andric // only determined when they are instantiated.
1670b57cec5SDimitry Andric if (FD->isDependentContext())
1680b57cec5SDimitry Andric return false;
1690b57cec5SDimitry Andric
1700b57cec5SDimitry Andric IdentifierInfo *II = FD->getIdentifier();
171*5f757f3fSDimitry Andric if (II && II->getName().starts_with("__inline"))
1720b57cec5SDimitry Andric return false;
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric return true;
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric
addNodeForDecl(Decl * D,bool IsGlobal)1780b57cec5SDimitry Andric void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
1790b57cec5SDimitry Andric assert(D);
1800b57cec5SDimitry Andric
181a7dea167SDimitry Andric // Allocate a new node, mark it as root, and process its calls.
1820b57cec5SDimitry Andric CallGraphNode *Node = getOrInsertNode(D);
1830b57cec5SDimitry Andric
1840b57cec5SDimitry Andric // Process all the calls by this function as well.
1850b57cec5SDimitry Andric CGBuilder builder(this, Node);
1860b57cec5SDimitry Andric if (Stmt *Body = D->getBody())
1870b57cec5SDimitry Andric builder.Visit(Body);
188a7dea167SDimitry Andric
189a7dea167SDimitry Andric // Include C++ constructor member initializers.
190a7dea167SDimitry Andric if (auto constructor = dyn_cast<CXXConstructorDecl>(D)) {
191a7dea167SDimitry Andric for (CXXCtorInitializer *init : constructor->inits()) {
192a7dea167SDimitry Andric builder.Visit(init->getInit());
193a7dea167SDimitry Andric }
194a7dea167SDimitry Andric }
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric
getNode(const Decl * F) const1970b57cec5SDimitry Andric CallGraphNode *CallGraph::getNode(const Decl *F) const {
1980b57cec5SDimitry Andric FunctionMapTy::const_iterator I = FunctionMap.find(F);
1990b57cec5SDimitry Andric if (I == FunctionMap.end()) return nullptr;
2000b57cec5SDimitry Andric return I->second.get();
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric
getOrInsertNode(Decl * F)2030b57cec5SDimitry Andric CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
2040b57cec5SDimitry Andric if (F && !isa<ObjCMethodDecl>(F))
2050b57cec5SDimitry Andric F = F->getCanonicalDecl();
2060b57cec5SDimitry Andric
2070b57cec5SDimitry Andric std::unique_ptr<CallGraphNode> &Node = FunctionMap[F];
2080b57cec5SDimitry Andric if (Node)
2090b57cec5SDimitry Andric return Node.get();
2100b57cec5SDimitry Andric
211a7dea167SDimitry Andric Node = std::make_unique<CallGraphNode>(F);
2120b57cec5SDimitry Andric // Make Root node a parent of all functions to make sure all are reachable.
2130b57cec5SDimitry Andric if (F)
2145ffd83dbSDimitry Andric Root->addCallee({Node.get(), /*Call=*/nullptr});
2150b57cec5SDimitry Andric return Node.get();
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric
print(raw_ostream & OS) const2180b57cec5SDimitry Andric void CallGraph::print(raw_ostream &OS) const {
2190b57cec5SDimitry Andric OS << " --- Call graph Dump --- \n";
2200b57cec5SDimitry Andric
2210b57cec5SDimitry Andric // We are going to print the graph in reverse post order, partially, to make
2220b57cec5SDimitry Andric // sure the output is deterministic.
2230b57cec5SDimitry Andric llvm::ReversePostOrderTraversal<const CallGraph *> RPOT(this);
2240b57cec5SDimitry Andric for (llvm::ReversePostOrderTraversal<const CallGraph *>::rpo_iterator
2250b57cec5SDimitry Andric I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
2260b57cec5SDimitry Andric const CallGraphNode *N = *I;
2270b57cec5SDimitry Andric
2280b57cec5SDimitry Andric OS << " Function: ";
2290b57cec5SDimitry Andric if (N == Root)
2300b57cec5SDimitry Andric OS << "< root >";
2310b57cec5SDimitry Andric else
2320b57cec5SDimitry Andric N->print(OS);
2330b57cec5SDimitry Andric
2340b57cec5SDimitry Andric OS << " calls: ";
2350b57cec5SDimitry Andric for (CallGraphNode::const_iterator CI = N->begin(),
2360b57cec5SDimitry Andric CE = N->end(); CI != CE; ++CI) {
2375ffd83dbSDimitry Andric assert(CI->Callee != Root && "No one can call the root node.");
2385ffd83dbSDimitry Andric CI->Callee->print(OS);
2390b57cec5SDimitry Andric OS << " ";
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric OS << '\n';
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric OS.flush();
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric
dump() const2460b57cec5SDimitry Andric LLVM_DUMP_METHOD void CallGraph::dump() const {
2470b57cec5SDimitry Andric print(llvm::errs());
2480b57cec5SDimitry Andric }
2490b57cec5SDimitry Andric
viewGraph() const2500b57cec5SDimitry Andric void CallGraph::viewGraph() const {
2510b57cec5SDimitry Andric llvm::ViewGraph(this, "CallGraph");
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric
print(raw_ostream & os) const2540b57cec5SDimitry Andric void CallGraphNode::print(raw_ostream &os) const {
2550b57cec5SDimitry Andric if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(FD))
2560b57cec5SDimitry Andric return ND->printQualifiedName(os);
2570b57cec5SDimitry Andric os << "< >";
2580b57cec5SDimitry Andric }
2590b57cec5SDimitry Andric
dump() const2600b57cec5SDimitry Andric LLVM_DUMP_METHOD void CallGraphNode::dump() const {
2610b57cec5SDimitry Andric print(llvm::errs());
2620b57cec5SDimitry Andric }
2630b57cec5SDimitry Andric
2640b57cec5SDimitry Andric namespace llvm {
2650b57cec5SDimitry Andric
2660b57cec5SDimitry Andric template <>
2670b57cec5SDimitry Andric struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits {
DOTGraphTraitsllvm::DOTGraphTraits2680b57cec5SDimitry Andric DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
2690b57cec5SDimitry Andric
getNodeLabelllvm::DOTGraphTraits2700b57cec5SDimitry Andric static std::string getNodeLabel(const CallGraphNode *Node,
2710b57cec5SDimitry Andric const CallGraph *CG) {
2720b57cec5SDimitry Andric if (CG->getRoot() == Node) {
2730b57cec5SDimitry Andric return "< root >";
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Node->getDecl()))
2760b57cec5SDimitry Andric return ND->getNameAsString();
2770b57cec5SDimitry Andric else
2780b57cec5SDimitry Andric return "< >";
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric };
2810b57cec5SDimitry Andric
2820b57cec5SDimitry Andric } // namespace llvm
283