diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Analysis/CallGraph.cpp | 81 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp | 48 |
2 files changed, 85 insertions, 44 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 "< >"; } }; diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 47ca9b7ba4..025891adf8 100644 --- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -330,6 +330,14 @@ public: } 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); @@ -544,16 +552,6 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { } -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(); @@ -591,6 +589,8 @@ AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) { 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; @@ -602,29 +602,17 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, 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++; + } } //===----------------------------------------------------------------------===// |