diff --git a/clang/include/clang/Analysis/CallGraph.h b/clang/include/clang/Analysis/CallGraph.h index 041050319239..6f7159330f5d 100644 --- a/clang/include/clang/Analysis/CallGraph.h +++ b/clang/include/clang/Analysis/CallGraph.h @@ -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; diff --git a/clang/lib/Analysis/CallGraph.cpp b/clang/lib/Analysis/CallGraph.cpp index 419f3ad2e724..59cc939b6fd1 100644 --- a/clang/lib/Analysis/CallGraph.cpp +++ b/clang/lib/Analysis/CallGraph.cpp @@ -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(D)) { // We skip function template definitions, as their semantics is // only determined when they are instantiated. diff --git a/clang/test/Analysis/debug-CallGraph.cpp b/clang/test/Analysis/debug-CallGraph.cpp index 5453e2f21533..120bb38d3bb3 100644 --- a/clang/test/Analysis/debug-CallGraph.cpp +++ b/clang/test/Analysis/debug-CallGraph.cpp @@ -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 $}}