void dump() const;
void viewGraph() const;
+ void addNodesForBlocks(DeclContext *D);
+
/// Part of recursive declaration visitation. We recursively visit all the
- /// Declarations to collect the root functions.
+ /// declarations to collect the root functions.
bool VisitFunctionDecl(FunctionDecl *FD) {
// We skip function template definitions, as their semantics is
// only determined when they are instantiated.
- if (includeInGraph(FD))
+ if (includeInGraph(FD)) {
+ // Add all blocks declared inside this function to the graph.
+ addNodesForBlocks(FD);
// If this function has external linkage, anything could call it.
// Note, we are not precise here. For example, the function could have
// its address taken.
addNodeForDecl(FD, FD->isGlobal());
+ }
return true;
}
/// Part of recursive declaration visitation.
bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
- if (includeInGraph(MD))
+ if (includeInGraph(MD)) {
+ addNodesForBlocks(MD);
addNodeForDecl(MD, true);
+ }
return true;
}
Decl *FD;
/// \brief The list of functions called from this node.
- // Small vector might be more efficient since we are only tracking functions
- // whose definition is in the current TU.
llvm::SmallVector<CallRecord, 5> CalledFunctions;
public:
Decl *getDecl() const { return FD; }
- StringRef getName() const;
-
void print(raw_ostream &os) const;
void dump() const;
};
// 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.
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) {
} // 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);
}
}
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.
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 {
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 "< >";
}
};
}
return true;
}
+
+ bool VisitBlockDecl(BlockDecl *BD) {
+ if (BD->hasBody()) {
+ assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
+ HandleCode(BD, RecVisitorMode);
+ }
+ return true;
+ }
private:
void storeTopLevelDecls(DeclGroupRef DG);
}
-static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) {
- if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
- WL.push_back(BD);
-
- for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
- I!=E; ++I)
- if (DeclContext *DC = dyn_cast<DeclContext>(*I))
- FindBlocks(DC, WL);
-}
-
static std::string getFunctionName(const Decl *D) {
if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
return ID->getSelector().getAsString();
void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
ExprEngine::InliningModes IMode,
SetOfConstDecls *VisitedCallees) {
+ if (!D->hasBody())
+ return;
Mode = getModeForDecl(D, Mode);
if (Mode == AM_None)
return;
MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize;
}
-
// Clear the AnalysisManager of old AnalysisDeclContexts.
Mgr->ClearContexts();
-
- // Dispatch on the actions.
- SmallVector<Decl*, 10> WL;
- WL.push_back(D);
-
- if (D->hasBody() && Opts->AnalyzeNestedBlocks)
- FindBlocks(cast<DeclContext>(D), WL);
-
BugReporter BR(*Mgr);
- for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
- WI != WE; ++WI)
- if ((*WI)->hasBody()) {
- if (Mode & AM_Syntax)
- checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
- if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
- RunPathSensitiveChecks(*WI, IMode, VisitedCallees);
- if (IMode != ExprEngine::Inline_None)
- NumFunctionsAnalyzed++;
- }
- }
+
+ if (Mode & AM_Syntax)
+ checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
+ if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
+ RunPathSensitiveChecks(D, IMode, VisitedCallees);
+ if (IMode != ExprEngine::Inline_None)
+ NumFunctionsAnalyzed++;
+ }
}
//===----------------------------------------------------------------------===//