diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp b/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp new file mode 100644 index 0000000..3387015 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp @@ -0,0 +1,237 @@ +//== CallGraph.cpp - AST-based Call graph ----------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/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. +class CGBuilder : public StmtVisitor<CGBuilder> { + CallGraph *G; + CallGraphNode *CallerNode; + +public: + CGBuilder(CallGraph *g, CallGraphNode *N) + : G(g), CallerNode(N) {} + + void VisitStmt(Stmt *S) { VisitChildren(S); } + + Decl *getDeclFromCall(CallExpr *CE) { + if (FunctionDecl *CalleeDecl = CE->getDirectCallee()) + 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) { + for (Stmt::child_range I = S->children(); I; ++I) + if (*I) + static_cast<CGBuilder*>(this)->Visit(*I); + } +}; + +} // 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); +} + +CallGraph::~CallGraph() { + if (!FunctionMap.empty()) { + for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end(); + I != E; ++I) + delete I->second; + FunctionMap.clear(); + } +} + +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. + if (!FD->isThisDeclarationADefinition() || + FD->isDependentContext()) + return false; + + IdentifierInfo *II = FD->getIdentifier(); + if (II && II->getName().startswith("__inline")) + return false; + } + + if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) { + if (!ID->isThisDeclarationADefinition()) + return false; + } + + return true; +} + +void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) { + assert(D); + + // Allocate a new node, mark it as root, and process it's calls. + CallGraphNode *Node = getOrInsertNode(D); + + // Process all the calls by this function as well. + CGBuilder builder(this, Node); + if (Stmt *Body = D->getBody()) + builder.Visit(Body); +} + +CallGraphNode *CallGraph::getNode(const Decl *F) const { + FunctionMapTy::const_iterator I = FunctionMap.find(F); + if (I == FunctionMap.end()) return 0; + return I->second; +} + +CallGraphNode *CallGraph::getOrInsertNode(Decl *F) { + CallGraphNode *&Node = FunctionMap[F]; + if (Node) + return Node; + + Node = new CallGraphNode(F); + // Make Root node a parent of all functions to make sure all are reachable. + if (F != 0) + Root->addCallee(Node, this); + return Node; +} + +void CallGraph::print(raw_ostream &OS) const { + OS << " --- Call graph Dump --- \n"; + + // 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 (N == Root) + OS << "< root >"; + else + N->print(OS); + + OS << " calls: "; + 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 << " "; + } + OS << '\n'; + } + OS.flush(); +} + +void CallGraph::dump() const { + print(llvm::errs()); +} + +void CallGraph::viewGraph() const { + llvm::ViewGraph(this, "CallGraph"); +} + +void CallGraphNode::print(raw_ostream &os) const { + if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(FD)) + return ND->printName(os); + os << "< >"; +} + +void CallGraphNode::dump() const { + print(llvm::errs()); +} + +namespace llvm { + +template <> +struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits { + + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + + static std::string getNodeLabel(const CallGraphNode *Node, + const CallGraph *CG) { + if (CG->getRoot() == Node) { + return "< root >"; + } + if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Node->getDecl())) + return ND->getNameAsString(); + else + return "< >"; + } + +}; +} |