aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/CallGraph.cpp
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-12-21 01:19:15 +0000
committerAnna Zaks <ganna@apple.com>2012-12-21 01:19:15 +0000
commit4f858dfd42c89b67200dac0afc228a0baa323691 (patch)
treead4d008b16fb3bc5ff7f057897561388d715d154 /lib/Analysis/CallGraph.cpp
parentcd0fd18909e3b89ed6f2cc1118809003db64e67a (diff)
[analyzer] Add blocks and ObjC messages to the call graph.
This paves the road for constructing a better function dependency graph. If we analyze a function before the functions it calls and inlines, there is more opportunity for optimization. Note, we add call edges to the called methods that correspond to function definitions (declarations with bodies). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@170825 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/CallGraph.cpp')
-rw-r--r--lib/Analysis/CallGraph.cpp81
1 files changed, 67 insertions, 14 deletions
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 12a6fe650f..424e5c795e 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -10,14 +10,20 @@
// This file defines the AST-based CallGraph.
//
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "CallGraph"
+
#include "clang/Analysis/CallGraph.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/Support/GraphWriter.h"
using namespace clang;
+STATISTIC(NumObjCCallEdges, "Number of objective C call edges");
+STATISTIC(NumBlockCallEdges, "Number of block call edges");
+
namespace {
/// A helper class, which walks the AST and locates all the call sites in the
/// given function body.
@@ -31,13 +37,48 @@ public:
void VisitStmt(Stmt *S) { VisitChildren(S); }
- void VisitCallExpr(CallExpr *CE) {
- // TODO: We need to handle ObjC method calls as well.
+ Decl *getDeclFromCall(CallExpr *CE) {
if (FunctionDecl *CalleeDecl = CE->getDirectCallee())
- if (G->includeInGraph(CalleeDecl)) {
- CallGraphNode *CalleeNode = G->getOrInsertNode(CalleeDecl);
- CallerNode->addCallee(CalleeNode, G);
+ return CalleeDecl;
+
+ // Simple detection of a call through a block.
+ Expr *CEE = CE->getCallee()->IgnoreParenImpCasts();
+ if (BlockExpr *Block = dyn_cast<BlockExpr>(CEE)) {
+ NumBlockCallEdges++;
+ return Block->getBlockDecl();
+ }
+
+ return 0;
+ }
+
+ void addCalledDecl(Decl *D) {
+ if (G->includeInGraph(D)) {
+ CallGraphNode *CalleeNode = G->getOrInsertNode(D);
+ CallerNode->addCallee(CalleeNode, G);
+ }
+ }
+
+ void VisitCallExpr(CallExpr *CE) {
+ if (Decl *D = getDeclFromCall(CE))
+ addCalledDecl(D);
+ }
+
+ // Adds may-call edges for the ObjC message sends.
+ void VisitObjCMessageExpr(ObjCMessageExpr *ME) {
+ if (ObjCInterfaceDecl *IDecl = ME->getReceiverInterface()) {
+ Selector Sel = ME->getSelector();
+
+ // Fild the callee definition within the same translation unit.
+ Decl *D = 0;
+ if (ME->isInstanceMessage())
+ D = IDecl->lookupPrivateMethod(Sel);
+ else
+ D = IDecl->lookupPrivateClassMethod(Sel);
+ if (D) {
+ addCalledDecl(D);
+ NumObjCCallEdges++;
}
+ }
}
void VisitChildren(Stmt *S) {
@@ -49,6 +90,16 @@ public:
} // end anonymous namespace
+void CallGraph::addNodesForBlocks(DeclContext *D) {
+ if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
+ addNodeForDecl(BD, true);
+
+ for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
+ I!=E; ++I)
+ if (DeclContext *DC = dyn_cast<DeclContext>(*I))
+ addNodesForBlocks(DC);
+}
+
CallGraph::CallGraph() {
Root = getOrInsertNode(0);
}
@@ -63,6 +114,10 @@ CallGraph::~CallGraph() {
}
bool CallGraph::includeInGraph(const Decl *D) {
+ assert(D);
+ if (!D->getBody())
+ return false;
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// We skip function template definitions, as their semantics is
// only determined when they are instantiated.
@@ -147,15 +202,10 @@ void CallGraph::viewGraph() const {
llvm::ViewGraph(this, "CallGraph");
}
-StringRef CallGraphNode::getName() const {
- if (const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(FD))
- if (const IdentifierInfo *II = D->getIdentifier())
- return II->getName();
- return "< >";
-}
-
void CallGraphNode::print(raw_ostream &os) const {
- os << getName();
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(FD))
+ return ND->printName(os);
+ os << "< >";
}
void CallGraphNode::dump() const {
@@ -174,7 +224,10 @@ struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits {
if (CG->getRoot() == Node) {
return "< root >";
}
- return Node->getName();
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Node->getDecl()))
+ return ND->getNameAsString();
+ else
+ return "< >";
}
};