[cfe-commits] r170825 - in /cfe/trunk: include/clang/Analysis/CallGraph.h lib/Analysis/CallGraph.cpp lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp

Anna Zaks ganna at apple.com
Thu Dec 20 17:19:15 PST 2012


Author: zaks
Date: Thu Dec 20 19:19:15 2012
New Revision: 170825

URL: http://llvm.org/viewvc/llvm-project?rev=170825&view=rev
Log:
[analyzer] Add blocks and ObjC messages to the call graph.

This paves the road for constructing a better function dependency graph.
If we analyze a function before the functions it calls and inlines,
there is more opportunity for optimization.

Note, we add call edges to the called methods that correspond to
function definitions (declarations with bodies).

Modified:
    cfe/trunk/include/clang/Analysis/CallGraph.h
    cfe/trunk/lib/Analysis/CallGraph.cpp
    cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp

Modified: cfe/trunk/include/clang/Analysis/CallGraph.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CallGraph.h?rev=170825&r1=170824&r2=170825&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/CallGraph.h (original)
+++ cfe/trunk/include/clang/Analysis/CallGraph.h Thu Dec 20 19:19:15 2012
@@ -102,23 +102,30 @@
   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;
   }
 
@@ -144,8 +151,6 @@
   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:
@@ -170,8 +175,6 @@
 
   Decl *getDecl() const { return FD; }
 
-  StringRef getName() const;
-
   void print(raw_ostream &os) const;
   void dump() const;
 };

Modified: cfe/trunk/lib/Analysis/CallGraph.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CallGraph.cpp?rev=170825&r1=170824&r2=170825&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CallGraph.cpp (original)
+++ cfe/trunk/lib/Analysis/CallGraph.cpp Thu Dec 20 19:19:15 2012
@@ -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 @@
 
   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 @@
 
 } // 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 @@
 }
 
 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 @@
   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 @@
     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 "< >";
   }
 
 };

Modified: cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp?rev=170825&r1=170824&r2=170825&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp Thu Dec 20 19:19:15 2012
@@ -330,6 +330,14 @@
     }
     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 @@
 
 }
 
-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 @@
 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 @@
     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++;
+  }
 }
 
 //===----------------------------------------------------------------------===//





More information about the cfe-commits mailing list