]> granicus.if.org Git - clang/commitdiff
[CallGraph] Take into accound calls that aren't within any function bodies.
authorArtem Dergachev <artem.dergachev@gmail.com>
Tue, 20 Aug 2019 02:22:37 +0000 (02:22 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Tue, 20 Aug 2019 02:22:37 +0000 (02:22 +0000)
This patch improves Clang call graph analysis by adding in expressions
that are not found in regular function bodies, such as default arguments
or member initializers.

Patch by Joshua Cranmer!

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@369321 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/CallGraph.h
lib/Analysis/CallGraph.cpp
test/Analysis/cxx-callgraph.cpp [new file with mode: 0644]
test/Analysis/exploded-graph-rewriter/objects_under_construction.cpp

index 49c04490fed2c3f0cfc75a3002fa22a042292193..dae2b58ffc10204a9ed5ae9aa62f0005d189bf03 100644 (file)
@@ -131,6 +131,7 @@ public:
 
   bool shouldWalkTypesOfTypeLocs() const { return false; }
   bool shouldVisitTemplateInstantiations() const { return true; }
+  bool shouldVisitImplicitCode() const { return true; }
 
 private:
   /// Add the given declaration to the call graph.
index 71219161d05f302044127a1f971e001cef199b8d..865840eb341a23f1be9f5ae3a519c4b23f3024c5 100644 (file)
@@ -79,6 +79,34 @@ public:
     VisitChildren(CE);
   }
 
+  void VisitLambdaExpr(LambdaExpr *LE) {
+    if (CXXMethodDecl *MD = LE->getCallOperator())
+      G->VisitFunctionDecl(MD);
+  }
+
+  void VisitCXXNewExpr(CXXNewExpr *E) {
+    if (FunctionDecl *FD = E->getOperatorNew())
+      addCalledDecl(FD);
+    VisitChildren(E);
+  }
+
+  void VisitCXXConstructExpr(CXXConstructExpr *E) {
+    CXXConstructorDecl *Ctor = E->getConstructor();
+    if (FunctionDecl *Def = Ctor->getDefinition())
+      addCalledDecl(Def);
+    VisitChildren(E);
+  }
+
+  // Include the evaluation of the default argument.
+  void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+    Visit(E->getExpr());
+  }
+
+  // Include the evaluation of the default initializers in a class.
+  void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
+    Visit(E->getExpr());
+  }
+
   // Adds may-call edges for the ObjC message sends.
   void VisitObjCMessageExpr(ObjCMessageExpr *ME) {
     if (ObjCInterfaceDecl *IDecl = ME->getReceiverInterface()) {
@@ -143,13 +171,20 @@ bool CallGraph::includeInGraph(const Decl *D) {
 void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
   assert(D);
 
-  // Allocate a new node, mark it as root, and process it's calls.
+  // Allocate a new node, mark it as root, and process its calls.
   CallGraphNode *Node = getOrInsertNode(D);
 
   // Process all the calls by this function as well.
   CGBuilder builder(this, Node);
   if (Stmt *Body = D->getBody())
     builder.Visit(Body);
+
+  // Include C++ constructor member initializers.
+  if (auto constructor = dyn_cast<CXXConstructorDecl>(D)) {
+    for (CXXCtorInitializer *init : constructor->inits()) {
+      builder.Visit(init->getInit());
+    }
+  }
 }
 
 CallGraphNode *CallGraph::getNode(const Decl *F) const {
diff --git a/test/Analysis/cxx-callgraph.cpp b/test/Analysis/cxx-callgraph.cpp
new file mode 100644 (file)
index 0000000..4a48e42
--- /dev/null
@@ -0,0 +1,29 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCallGraph %s 2>&1 | FileCheck %s
+
+static int aaa() {
+  return 0;
+}
+
+static int bbb(int param=aaa()) {
+  return 1;
+}
+
+int ddd();
+
+struct c {
+  c(int param=2) : val(bbb(param)) {}
+  int val;
+  int val2 = ddd();
+};
+
+int ddd() {
+  c c;
+  return bbb();
+}
+
+// CHECK:--- Call graph Dump ---
+// CHECK-NEXT: {{Function: < root > calls: aaa bbb c::c ddd}}
+// CHECK-NEXT: {{Function: c::c calls: bbb ddd $}}
+// CHECK-NEXT: {{Function: ddd calls: c::c bbb aaa $}}
+// CHECK-NEXT: {{Function: bbb calls: $}}
+// CHECK-NEXT: {{Function: aaa calls: $}}
index b3d4aef8bc8cf609e26859c59a7e71ae286f4ef5..e4d256247f98ad0e4c2d48202f4345b3742b9795 100644 (file)
@@ -1,5 +1,6 @@
 // FIXME: Figure out how to use %clang_analyze_cc1 with our lit.local.cfg.
 // RUN: %clang_cc1 -analyze -triple x86_64-unknown-linux-gnu \
+// RUN:                     -analyze-function "test()" \
 // RUN:                     -analyzer-checker=core \
 // RUN:                     -analyzer-dump-egraph=%t.dot %s
 // RUN: %exploded_graph_rewriter %t.dot | FileCheck %s