[clang] d68c7b8 - [clang][Analysis] CallGraph: store the actual call `Expr*` in the CallGraphNode::CallRecord
Roman Lebedev via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 13 12:38:06 PST 2020
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';
More information about the cfe-commits
mailing list