Author: Roman Lebedev
Date: 2020-02-13T23:37:53+03:00
New Revision: d68c7b8e3e4d605912ed36a843bbbcaa36234461

URL: 
https://github.com/llvm/llvm-project/commit/d68c7b8e3e4d605912ed36a843bbbcaa36234461
DIFF: 
https://github.com/llvm/llvm-project/commit/d68c7b8e3e4d605912ed36a843bbbcaa36234461.diff

LOG: [clang][Analysis] CallGraph: store the actual call `Expr*` in the 
CallGraphNode::CallRecord

Summary:
Storing not just the callee, but the actual call may be interesting for some 
use-cases.
In particular, D72362 would like that to better pretty-print the cycles in call 
graph.

Reviewers: NoQ, erichkeane

Reviewed By: NoQ

Subscribers: martong, Charusso, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D74081

Added: 
    

Modified: 
    clang-tools-extra/clang-move/HelperDeclRefGraph.cpp
    clang/include/clang/Analysis/CallGraph.h
    clang/lib/Analysis/CallGraph.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp 
b/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp
index 5495ae044584..271bd3d6ef20 100644
--- a/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp
+++ b/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp
@@ -27,7 +27,7 @@ void HelperDeclRefGraph::print(raw_ostream &OS) const {
     OS << " (" << N << ") ";
     OS << " calls: ";
     for (auto CI = N->begin(), CE = N->end(); CI != CE; ++CI) {
-      (*CI)->print(OS);
+      CI->Callee->print(OS);
       OS << " (" << CI << ") ";
     }
     OS << '\n';
@@ -48,7 +48,7 @@ void HelperDeclRefGraph::addEdge(const Decl *Caller, const 
Decl *Callee) {
   // Allocate a new node, mark it as root, and process it's calls.
   CallGraphNode *CallerNode = getOrInsertNode(const_cast<Decl *>(Caller));
   CallGraphNode *CalleeNode = getOrInsertNode(const_cast<Decl *>(Callee));
-  CallerNode->addCallee(CalleeNode);
+  CallerNode->addCallee({CalleeNode, /*CallExpr=*/nullptr});
 }
 
 void HelperDeclRefGraph::dump() const { print(llvm::errs()); }

diff  --git a/clang/include/clang/Analysis/CallGraph.h 
b/clang/include/clang/Analysis/CallGraph.h
index dae2b58ffc10..0e56d1c00623 100644
--- a/clang/include/clang/Analysis/CallGraph.h
+++ b/clang/include/clang/Analysis/CallGraph.h
@@ -24,6 +24,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/iterator_range.h"
 #include <memory>
 
 namespace clang {
@@ -136,14 +137,23 @@ class CallGraph : public RecursiveASTVisitor<CallGraph> {
 private:
   /// Add the given declaration to the call graph.
   void addNodeForDecl(Decl *D, bool IsGlobal);
-
-  /// Allocate a new node in the graph.
-  CallGraphNode *allocateNewNode(Decl *);
 };
 
 class CallGraphNode {
 public:
-  using CallRecord = CallGraphNode *;
+  struct CallRecord {
+    CallGraphNode *Callee;
+    Expr *CallExpr;
+
+    CallRecord() = default;
+
+    CallRecord(CallGraphNode *Callee_, Expr *CallExpr_)
+        : Callee(Callee_), CallExpr(CallExpr_) {}
+
+    // The call destination is the only important data here,
+    // allow to transparently unwrap into it.
+    operator CallGraphNode *() const { return Callee; }
+  };
 
 private:
   /// The function/method declaration.
@@ -164,12 +174,18 @@ class CallGraphNode {
   const_iterator begin() const { return CalledFunctions.begin(); }
   const_iterator end() const { return CalledFunctions.end(); }
 
+  /// Iterator access to callees/children of the node.
+  llvm::iterator_range<iterator> callees() {
+    return llvm::make_range(begin(), end());
+  }
+  llvm::iterator_range<const_iterator> callees() const {
+    return llvm::make_range(begin(), end());
+  }
+
   bool empty() const { return CalledFunctions.empty(); }
   unsigned size() const { return CalledFunctions.size(); }
 
-  void addCallee(CallGraphNode *N) {
-    CalledFunctions.push_back(N);
-  }
+  void addCallee(CallRecord Call) { CalledFunctions.push_back(Call); }
 
   Decl *getDecl() const { return FD; }
 
@@ -177,11 +193,44 @@ class CallGraphNode {
   void dump() const;
 };
 
+// NOTE: we are comparing based on the callee only. So 
diff erent call records
+// (with 
diff erent call expressions) to the same callee will compare equal!
+inline bool operator==(const CallGraphNode::CallRecord &LHS,
+                       const CallGraphNode::CallRecord &RHS) {
+  return LHS.Callee == RHS.Callee;
+}
+
 } // namespace clang
 
-// Graph traits for iteration, viewing.
 namespace llvm {
 
+// Specialize DenseMapInfo for clang::CallGraphNode::CallRecord.
+template <> struct DenseMapInfo<clang::CallGraphNode::CallRecord> {
+  static inline clang::CallGraphNode::CallRecord getEmptyKey() {
+    return clang::CallGraphNode::CallRecord(
+        DenseMapInfo<clang::CallGraphNode *>::getEmptyKey(),
+        DenseMapInfo<clang::Expr *>::getEmptyKey());
+  }
+
+  static inline clang::CallGraphNode::CallRecord getTombstoneKey() {
+    return clang::CallGraphNode::CallRecord(
+        DenseMapInfo<clang::CallGraphNode *>::getTombstoneKey(),
+        DenseMapInfo<clang::Expr *>::getTombstoneKey());
+  }
+
+  static unsigned getHashValue(const clang::CallGraphNode::CallRecord &Val) {
+    // NOTE: we are comparing based on the callee only.
+    // Different call records with the same callee will compare equal!
+    return DenseMapInfo<clang::CallGraphNode *>::getHashValue(Val.Callee);
+  }
+
+  static bool isEqual(const clang::CallGraphNode::CallRecord &LHS,
+                      const clang::CallGraphNode::CallRecord &RHS) {
+    return LHS == RHS;
+  }
+};
+
+// Graph traits for iteration, viewing.
 template <> struct GraphTraits<clang::CallGraphNode*> {
   using NodeType = clang::CallGraphNode;
   using NodeRef = clang::CallGraphNode *;

diff  --git a/clang/lib/Analysis/CallGraph.cpp 
b/clang/lib/Analysis/CallGraph.cpp
index 76be292dad8d..419f3ad2e724 100644
--- a/clang/lib/Analysis/CallGraph.cpp
+++ b/clang/lib/Analysis/CallGraph.cpp
@@ -66,16 +66,16 @@ class CGBuilder : public StmtVisitor<CGBuilder> {
     return nullptr;
   }
 
-  void addCalledDecl(Decl *D) {
+  void addCalledDecl(Decl *D, Expr *CallExpr) {
     if (G->includeInGraph(D)) {
       CallGraphNode *CalleeNode = G->getOrInsertNode(D);
-      CallerNode->addCallee(CalleeNode);
+      CallerNode->addCallee({CalleeNode, CallExpr});
     }
   }
 
   void VisitCallExpr(CallExpr *CE) {
     if (Decl *D = getDeclFromCall(CE))
-      addCalledDecl(D);
+      addCalledDecl(D, CE);
     VisitChildren(CE);
   }
 
@@ -89,14 +89,14 @@ class CGBuilder : public StmtVisitor<CGBuilder> {
 
   void VisitCXXNewExpr(CXXNewExpr *E) {
     if (FunctionDecl *FD = E->getOperatorNew())
-      addCalledDecl(FD);
+      addCalledDecl(FD, E);
     VisitChildren(E);
   }
 
   void VisitCXXConstructExpr(CXXConstructExpr *E) {
     CXXConstructorDecl *Ctor = E->getConstructor();
     if (FunctionDecl *Def = Ctor->getDefinition())
-      addCalledDecl(Def);
+      addCalledDecl(Def, E);
     VisitChildren(E);
   }
 
@@ -122,7 +122,7 @@ class CGBuilder : public StmtVisitor<CGBuilder> {
       else
         D = IDecl->lookupPrivateClassMethod(Sel);
       if (D) {
-        addCalledDecl(D);
+        addCalledDecl(D, ME);
         NumObjCCallEdges++;
       }
     }
@@ -207,7 +207,7 @@ CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
   Node = std::make_unique<CallGraphNode>(F);
   // Make Root node a parent of all functions to make sure all are reachable.
   if (F)
-    Root->addCallee(Node.get());
+    Root->addCallee({Node.get(), /*Call=*/nullptr});
   return Node.get();
 }
 
@@ -230,8 +230,8 @@ void CallGraph::print(raw_ostream &OS) const {
     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);
+      assert(CI->Callee != Root && "No one can call the root node.");
+      CI->Callee->print(OS);
       OS << " ";
     }
     OS << '\n';


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to