diff options
Diffstat (limited to 'clang/lib/Analysis/CallGraph.cpp')
-rw-r--r-- | clang/lib/Analysis/CallGraph.cpp | 81 |
1 files changed, 67 insertions, 14 deletions
diff --git a/clang/lib/Analysis/CallGraph.cpp b/clang/lib/Analysis/CallGraph.cpp index 12a6fe650ff..424e5c795e2 100644 --- a/clang/lib/Analysis/CallGraph.cpp +++ b/clang/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 "< >"; } }; |