aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/CallGraph.cpp
blob: 2530fc0ad74410fc8ace858893c6f407763d74ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//== CallGraph.cpp - Call graph building ------------------------*- C++ -*--==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defined the CallGraph and CGBuilder classes.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/CallGraph.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/StmtVisitor.h"

using namespace clang;
using namespace idx;

namespace {
class CGBuilder : public StmtVisitor<CGBuilder> {

  CallGraph &G;
  FunctionDecl *FD;

  Entity CallerEnt;

  CallGraphNode *CallerNode;

public:
  CGBuilder(CallGraph &g, FunctionDecl *fd, Entity E, CallGraphNode *N)
    : G(g), FD(fd), CallerEnt(E), CallerNode(N) {}

  void VisitStmt(Stmt *S) { VisitChildren(S); }

  void VisitCallExpr(CallExpr *CE);

  void VisitChildren(Stmt *S) {
    for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I)
      if (*I) 
        static_cast<CGBuilder*>(this)->Visit(*I);    
  }
};
}

void CGBuilder::VisitCallExpr(CallExpr *CE) {
  if (FunctionDecl *CalleeDecl = CE->getDirectCallee()) {
    Entity Ent = Entity::get(CalleeDecl, G.getProgram());
    CallGraphNode *CalleeNode = G.getOrInsertFunction(Ent);

    Decl *Parent = ASTLocation::FindImmediateParent(FD, CE);
    
    CallerNode->addCallee(ASTLocation(Parent, CE), CalleeNode);
  }
}

CallGraph::~CallGraph() {
  if (!FunctionMap.empty()) {
    for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
        I != E; ++I)
      delete I->second;
    FunctionMap.clear();
  }
}

void CallGraph::addTU(ASTUnit &AST) {
  ASTContext &Ctx = AST.getASTContext();
  DeclContext *DC = Ctx.getTranslationUnitDecl();

  for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
       I != E; ++I) {

    if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
      if (FD->isThisDeclarationADefinition()) {
        // Set caller's ASTContext.
        Entity Ent = Entity::get(FD, Prog);
        CallGraphNode *Node = getOrInsertFunction(Ent);
        CallerCtx[Node] = &Ctx;
        
        CGBuilder builder(*this, FD, Ent, Node);
        builder.Visit(FD->getBody());
      }
    }
  }
}

CallGraphNode *CallGraph::getOrInsertFunction(Entity F) {
  CallGraphNode *&Node = FunctionMap[F];
  if (Node)
    return Node;

  return Node = new CallGraphNode(F);
}

void CallGraph::print(llvm::raw_ostream &os) {
  for (iterator I = begin(), E = end(); I != E; ++I) {
    if (I->second->hasCallee()) {
      ASTContext &Ctx = *CallerCtx[I->second];
      os << "function: " << I->first.getPrintableName(Ctx).c_str() 
         << " calls:\n";
      for (CallGraphNode::iterator CI = I->second->begin(), 
             CE = I->second->end(); CI != CE; ++CI) {
        os << "    " << CI->second->getName(Ctx).c_str();
      }
      os << '\n';
    }
  }
}

void CallGraph::dump() {
  print(llvm::errs());
}