[[Clang CallGraph]] CallGraph should still record calls to decls.

Discovered by a downstream user, we found that the CallGraph ignores
callees unless they are defined.  This seems foolish, and prevents
combining the report with other reports to create unified reports.
Additionally, declarations contain information that is likely useful to
consumers of the CallGraph.

This patch implements this by splitting the includeInGraph function into
two versions, the current one plus one that is for callees only.  The
only difference currently is that includeInGraph checks for a body, then
calls includeCalleeInGraph.

Differential Revision: https://reviews.llvm.org/D76435
This commit is contained in:
Erich Keane 2020-03-19 09:45:04 -07:00
parent 34659de5fd
commit ffcc076a2b
3 changed files with 13 additions and 3 deletions

View File

@ -66,6 +66,11 @@ public:
/// Determine if a declaration should be included in the graph.
static bool includeInGraph(const Decl *D);
/// Determine if a declaration should be included in the graph for the
/// purposes of being a callee. This is similar to includeInGraph except
/// it permits declarations, not just definitions.
static bool includeCalleeInGraph(const Decl *D);
/// Lookup the node for the given declaration.
CallGraphNode *getNode(const Decl *) const;

View File

@ -67,7 +67,7 @@ public:
}
void addCalledDecl(Decl *D, Expr *CallExpr) {
if (G->includeInGraph(D)) {
if (G->includeCalleeInGraph(D)) {
CallGraphNode *CalleeNode = G->getOrInsertNode(D);
CallerNode->addCallee({CalleeNode, CallExpr});
}
@ -157,6 +157,10 @@ bool CallGraph::includeInGraph(const Decl *D) {
if (!D->hasBody())
return false;
return includeCalleeInGraph(D);
}
bool CallGraph::includeCalleeInGraph(const Decl *D) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// We skip function template definitions, as their semantics is
// only determined when they are instantiated.

View File

@ -97,9 +97,10 @@ namespace CallDecl {
}
// CHECK:--- Call graph Dump ---
// CHECK-NEXT: {{Function: < root > calls: get5 add test_add mmm foo aaa < > bbb ddd ccc eee fff do_nothing test_single_call SomeNS::templ SomeNS::templ SomeNS::templUser Lambdas::Callee Lambdas::f1 Lambdas::f1\(\)::\(anonymous class\)::operator\(\) Lambdas::f1\(\)::\(anonymous class\)::operator\(\) CallDecl::SomeDef CallDecl::Caller CallDecl::SomeOtherDecl $}}
// CHECK-NEXT: {{Function: CallDecl::Caller calls: CallDecl::SomeOtherDecl $}}
// CHECK-NEXT: {{Function: < root > calls: get5 add test_add mmm foo aaa < > bbb ddd ccc eee fff do_nothing test_single_call SomeNS::templ SomeNS::templ SomeNS::templUser Lambdas::Callee Lambdas::f1 Lambdas::f1\(\)::\(anonymous class\)::operator\(\) Lambdas::f1\(\)::\(anonymous class\)::operator\(\) CallDecl::SomeDef CallDecl::Caller CallDecl::SomeDecl CallDecl::SomeOtherDecl $}}
// CHECK-NEXT: {{Function: CallDecl::Caller calls: CallDecl::SomeDecl CallDecl::SomeOtherDecl $}}
// CHECK-NEXT: {{Function: CallDecl::SomeOtherDecl calls: CallDecl::SomeDef $}}
// CHECK-NEXT: {{Function: CallDecl::SomeDecl calls: $}}
// CHECK-NEXT: {{Function: CallDecl::SomeDef calls: $}}
// CHECK-NEXT: {{Function: Lambdas::f1 calls: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) Lambdas::f1\(\)::\(anonymous class\)::operator\(\) $}}
// CHECK-NEXT: {{Function: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) calls: Lambdas::Callee $}}