diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp | 112 |
1 files changed, 83 insertions, 29 deletions
diff --git a/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp b/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp index 6b75956..3387015 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp @@ -10,16 +10,21 @@ // This file defines the AST-based CallGraph. // //===----------------------------------------------------------------------===// -#include "clang/Analysis/CallGraph.h" +#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/PostOrderIterator.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Support/GraphWriter.h" using namespace clang; +STATISTIC(NumObjCCallEdges, "Number of Objective-C method 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. @@ -33,13 +38,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(); + + // Find 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) { @@ -51,6 +91,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); } @@ -65,6 +115,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. @@ -88,14 +142,8 @@ bool CallGraph::includeInGraph(const Decl *D) { void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) { assert(D); - // Do nothing if the node already exists. - if (FunctionMap.find(D) != FunctionMap.end()) - return; - // Allocate a new node, mark it as root, and process it's calls. CallGraphNode *Node = getOrInsertNode(D); - if (IsGlobal) - Root->addCallee(Node, this); // Process all the calls by this function as well. CGBuilder builder(this, Node); @@ -115,23 +163,31 @@ CallGraphNode *CallGraph::getOrInsertNode(Decl *F) { return Node; Node = new CallGraphNode(F); - // If not root, add to the parentless list. + // Make Root node a parent of all functions to make sure all are reachable. if (F != 0) - ParentlessNodes.insert(Node); + Root->addCallee(Node, this); return Node; } void CallGraph::print(raw_ostream &OS) const { OS << " --- Call graph Dump --- \n"; - for (const_iterator I = begin(), E = end(); I != E; ++I) { + + // We are going to print the graph in reverse post order, partially, to make + // sure the output is deterministic. + llvm::ReversePostOrderTraversal<const clang::CallGraph*> RPOT(this); + for (llvm::ReversePostOrderTraversal<const clang::CallGraph*>::rpo_iterator + I = RPOT.begin(), E = RPOT.end(); I != E; ++I) { + const CallGraphNode *N = *I; + OS << " Function: "; - if (I->second == Root) + if (N == Root) OS << "< root >"; else - I->second->print(OS); + N->print(OS); + OS << " calls: "; - for (CallGraphNode::iterator CI = I->second->begin(), - CE = I->second->end(); CI != CE; ++CI) { + for (CallGraphNode::const_iterator CI = N->begin(), + CE = N->end(); CI != CE; ++CI) { assert(*CI != Root && "No one can call the root node."); (*CI)->print(OS); OS << " "; @@ -149,15 +205,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 { @@ -176,7 +227,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 "< >"; } }; |