summaryrefslogtreecommitdiffstats
path: root/clang/lib/Index/GlobalCallGraph.cpp
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-03-02 22:54:36 +0000
committerAnna Zaks <ganna@apple.com>2012-03-02 22:54:36 +0000
commitfc5dfe9f7cafebfc0b8cdee36082a6ef5eb24488 (patch)
tree70d0dea7a4565fa5b4129cca8ce175d4018a4df4 /clang/lib/Index/GlobalCallGraph.cpp
parent611306eae6c901916443b528b4fe789fd1574a90 (diff)
downloadbcm5719-llvm-fc5dfe9f7cafebfc0b8cdee36082a6ef5eb24488.tar.gz
bcm5719-llvm-fc5dfe9f7cafebfc0b8cdee36082a6ef5eb24488.zip
[analyzer] Rename clang::CallGraph into clang::idx::CallGraph + rename
the corresponding files to avoid confusion. This is a preparation to adding an AST-based call graph to Analysis. The existing call graph works with indexer entries. We might be able to refactor it to use the AST based graph in the future. (Minimal testing here as the only example that uses the API has been completely broken, does not compile.) llvm-svn: 151950
Diffstat (limited to 'clang/lib/Index/GlobalCallGraph.cpp')
-rw-r--r--clang/lib/Index/GlobalCallGraph.cpp152
1 files changed, 152 insertions, 0 deletions
diff --git a/clang/lib/Index/GlobalCallGraph.cpp b/clang/lib/Index/GlobalCallGraph.cpp
new file mode 100644
index 00000000000..a21b52ae602
--- /dev/null
+++ b/clang/lib/Index/GlobalCallGraph.cpp
@@ -0,0 +1,152 @@
+//== GlobalCallGraph.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/Index/GlobalCallGraph.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/StmtVisitor.h"
+
+#include "llvm/Support/GraphWriter.h"
+
+using namespace clang::idx;
+using clang::FunctionDecl;
+using clang::DeclContext;
+using clang::ASTContext;
+
+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_range I = S->children(); I; ++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);
+ CallerNode->addCallee(ASTLocation(FD, CE), CalleeNode);
+ }
+}
+
+CallGraph::CallGraph(Program &P) : Prog(P), Root(0) {
+ ExternalCallingNode = getOrInsertFunction(Entity());
+}
+
+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(ASTContext& Ctx) {
+ 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->doesThisDeclarationHaveABody()) {
+ // Set caller's ASTContext.
+ Entity Ent = Entity::get(FD, Prog);
+ CallGraphNode *Node = getOrInsertFunction(Ent);
+ CallerCtx[Node] = &Ctx;
+
+ // If this function has external linkage, anything could call it.
+ if (FD->isGlobal())
+ ExternalCallingNode->addCallee(idx::ASTLocation(), Node);
+
+ // Set root node to 'main' function.
+ if (FD->getNameAsString() == "main")
+ Root = Node;
+
+ 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);
+}
+
+Decl *CallGraph::getDecl(CallGraphNode *Node) {
+ // Get the function's context.
+ ASTContext *Ctx = CallerCtx[Node];
+
+ return Node->getDecl(*Ctx);
+}
+
+void CallGraph::print(raw_ostream &os) {
+ for (iterator I = begin(), E = end(); I != E; ++I) {
+ if (I->second->hasCallee()) {
+ os << "function: " << I->first.getPrintableName()
+ << " calls:\n";
+ for (CallGraphNode::iterator CI = I->second->begin(),
+ CE = I->second->end(); CI != CE; ++CI) {
+ os << " " << CI->second->getName();
+ }
+ os << '\n';
+ }
+ }
+}
+
+void CallGraph::dump() {
+ print(llvm::errs());
+}
+
+void CallGraph::ViewCallGraph() const {
+ llvm::ViewGraph(*this, "CallGraph");
+}
+
+namespace llvm {
+
+template <>
+struct DOTGraphTraits<CallGraph> : public DefaultDOTGraphTraits {
+
+ DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+
+ static std::string getNodeLabel(const CallGraphNode *Node,
+ const CallGraph &CG) {
+ return Node->getName();
+
+ }
+
+};
+
+}
OpenPOWER on IntegriCloud