Home | History | Annotate | Line # | Download | only in Analysis
CallGraph.cpp revision 1.1
      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  joerg   void addCalledDecl(Decl *D) {
     70  1.1  joerg     if (G->includeInGraph(D)) {
     71  1.1  joerg       CallGraphNode *CalleeNode = G->getOrInsertNode(D);
     72  1.1  joerg       CallerNode->addCallee(CalleeNode);
     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  joerg       addCalledDecl(D);
     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  joerg       addCalledDecl(FD);
     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  joerg       addCalledDecl(Def);
    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  joerg         addCalledDecl(D);
    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  joerg   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
    161  1.1  joerg     // We skip function template definitions, as their semantics is
    162  1.1  joerg     // only determined when they are instantiated.
    163  1.1  joerg     if (FD->isDependentContext())
    164  1.1  joerg       return false;
    165  1.1  joerg 
    166  1.1  joerg     IdentifierInfo *II = FD->getIdentifier();
    167  1.1  joerg     if (II && II->getName().startswith("__inline"))
    168  1.1  joerg       return false;
    169  1.1  joerg   }
    170  1.1  joerg 
    171  1.1  joerg   return true;
    172  1.1  joerg }
    173  1.1  joerg 
    174  1.1  joerg void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
    175  1.1  joerg   assert(D);
    176  1.1  joerg 
    177  1.1  joerg   // Allocate a new node, mark it as root, and process its calls.
    178  1.1  joerg   CallGraphNode *Node = getOrInsertNode(D);
    179  1.1  joerg 
    180  1.1  joerg   // Process all the calls by this function as well.
    181  1.1  joerg   CGBuilder builder(this, Node);
    182  1.1  joerg   if (Stmt *Body = D->getBody())
    183  1.1  joerg     builder.Visit(Body);
    184  1.1  joerg 
    185  1.1  joerg   // Include C++ constructor member initializers.
    186  1.1  joerg   if (auto constructor = dyn_cast<CXXConstructorDecl>(D)) {
    187  1.1  joerg     for (CXXCtorInitializer *init : constructor->inits()) {
    188  1.1  joerg       builder.Visit(init->getInit());
    189  1.1  joerg     }
    190  1.1  joerg   }
    191  1.1  joerg }
    192  1.1  joerg 
    193  1.1  joerg CallGraphNode *CallGraph::getNode(const Decl *F) const {
    194  1.1  joerg   FunctionMapTy::const_iterator I = FunctionMap.find(F);
    195  1.1  joerg   if (I == FunctionMap.end()) return nullptr;
    196  1.1  joerg   return I->second.get();
    197  1.1  joerg }
    198  1.1  joerg 
    199  1.1  joerg CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
    200  1.1  joerg   if (F && !isa<ObjCMethodDecl>(F))
    201  1.1  joerg     F = F->getCanonicalDecl();
    202  1.1  joerg 
    203  1.1  joerg   std::unique_ptr<CallGraphNode> &Node = FunctionMap[F];
    204  1.1  joerg   if (Node)
    205  1.1  joerg     return Node.get();
    206  1.1  joerg 
    207  1.1  joerg   Node = std::make_unique<CallGraphNode>(F);
    208  1.1  joerg   // Make Root node a parent of all functions to make sure all are reachable.
    209  1.1  joerg   if (F)
    210  1.1  joerg     Root->addCallee(Node.get());
    211  1.1  joerg   return Node.get();
    212  1.1  joerg }
    213  1.1  joerg 
    214  1.1  joerg void CallGraph::print(raw_ostream &OS) const {
    215  1.1  joerg   OS << " --- Call graph Dump --- \n";
    216  1.1  joerg 
    217  1.1  joerg   // We are going to print the graph in reverse post order, partially, to make
    218  1.1  joerg   // sure the output is deterministic.
    219  1.1  joerg   llvm::ReversePostOrderTraversal<const CallGraph *> RPOT(this);
    220  1.1  joerg   for (llvm::ReversePostOrderTraversal<const CallGraph *>::rpo_iterator
    221  1.1  joerg          I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
    222  1.1  joerg     const CallGraphNode *N = *I;
    223  1.1  joerg 
    224  1.1  joerg     OS << "  Function: ";
    225  1.1  joerg     if (N == Root)
    226  1.1  joerg       OS << "< root >";
    227  1.1  joerg     else
    228  1.1  joerg       N->print(OS);
    229  1.1  joerg 
    230  1.1  joerg     OS << " calls: ";
    231  1.1  joerg     for (CallGraphNode::const_iterator CI = N->begin(),
    232  1.1  joerg                                        CE = N->end(); CI != CE; ++CI) {
    233  1.1  joerg       assert(*CI != Root && "No one can call the root node.");
    234  1.1  joerg       (*CI)->print(OS);
    235  1.1  joerg       OS << " ";
    236  1.1  joerg     }
    237  1.1  joerg     OS << '\n';
    238  1.1  joerg   }
    239  1.1  joerg   OS.flush();
    240  1.1  joerg }
    241  1.1  joerg 
    242  1.1  joerg LLVM_DUMP_METHOD void CallGraph::dump() const {
    243  1.1  joerg   print(llvm::errs());
    244  1.1  joerg }
    245  1.1  joerg 
    246  1.1  joerg void CallGraph::viewGraph() const {
    247  1.1  joerg   llvm::ViewGraph(this, "CallGraph");
    248  1.1  joerg }
    249  1.1  joerg 
    250  1.1  joerg void CallGraphNode::print(raw_ostream &os) const {
    251  1.1  joerg   if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(FD))
    252  1.1  joerg       return ND->printQualifiedName(os);
    253  1.1  joerg   os << "< >";
    254  1.1  joerg }
    255  1.1  joerg 
    256  1.1  joerg LLVM_DUMP_METHOD void CallGraphNode::dump() const {
    257  1.1  joerg   print(llvm::errs());
    258  1.1  joerg }
    259  1.1  joerg 
    260  1.1  joerg namespace llvm {
    261  1.1  joerg 
    262  1.1  joerg template <>
    263  1.1  joerg struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits {
    264  1.1  joerg   DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
    265  1.1  joerg 
    266  1.1  joerg   static std::string getNodeLabel(const CallGraphNode *Node,
    267  1.1  joerg                                   const CallGraph *CG) {
    268  1.1  joerg     if (CG->getRoot() == Node) {
    269  1.1  joerg       return "< root >";
    270  1.1  joerg     }
    271  1.1  joerg     if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Node->getDecl()))
    272  1.1  joerg       return ND->getNameAsString();
    273  1.1  joerg     else
    274  1.1  joerg       return "< >";
    275  1.1  joerg   }
    276  1.1  joerg };
    277  1.1  joerg 
    278  1.1  joerg } // namespace llvm
    279