Szelethus updated this revision to Diff 204554.
Szelethus added a comment.

- Resolved some reviewer comments
- Added a `BugReport` level set to avoid tracking the same condition (which 
would result in an almost infinite loop)

Aaaand I have some results to show: http://cc.elte.hu:15001/Default/#

Sort by "Storage date", and look for "LLVM/Clang/Clang-tools-extra BEFORE 
tracking conditions" and "LLVM/Clang/Clang-tools-extra AFTER tracking 
conditions". I didn't have much time to draw conclusions yet, but it's clear 
that the amount of extra notes are intolerable.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D62883/new/

https://reviews.llvm.org/D62883

Files:
  clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
  clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
  clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
  clang/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist
  clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
  clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist
  clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist
  clang/test/Analysis/Inputs/expected-plists/unix-fns.c.plist
  
clang/test/Analysis/diagnostics/Inputs/expected-plists/undef-value-param.m.plist
  clang/test/Analysis/diagnostics/no-store-func-path-notes.m
  clang/test/Analysis/diagnostics/undef-value-param.m
  clang/test/Analysis/track-control-dependency-conditions.cpp

Index: clang/test/Analysis/track-control-dependency-conditions.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/track-control-dependency-conditions.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_analyze_cc1 %s -verify \
+// RUN:   -analyzer-output=text \
+// RUN:   -analyzer-checker=core
+
+namespace example_1 {
+int flag;
+bool coin();
+
+void foo() {
+  flag = coin(); // expected-note {{Value assigned to 'flag'}}
+}
+
+void test() {
+  int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
+  flag = 1;
+
+  foo(); // TODO: Add nodes here about flag's value being invalidated.
+  if (flag) // expected-note   {{Taking false branch}}
+            // expected-note@-1{{Assuming 'flag' is 0}}
+    x = new int;
+
+  foo(); // expected-note   {{Calling 'foo'}}
+         // expected-note@-1{{Returning from 'foo'}}
+
+  if (flag) // expected-note   {{Taking true branch}}
+            // expected-note@-1{{Assuming 'flag' is not equal to 0}}
+    *x = 5; // expected-warning{{Dereference of null pointer}}
+            // expected-note@-1{{Dereference of null pointer}}
+}
+} // end of namespace example_1
+
+namespace example_2 {
+int flag;
+bool coin();
+
+void foo() {
+  flag = coin(); // expected-note {{Value assigned to 'flag'}}
+}
+
+void test() {
+  int *x = 0;
+  flag = 1;
+
+  foo(); // TODO: Add nodes here about flag's value being invalidated.
+  if (flag) // expected-note   {{Taking false branch}}
+            // expected-note@-1{{Assuming 'flag' is 0}}
+    x = new int;
+
+  x = 0; // expected-note{{Null pointer value stored to 'x'}}
+
+  foo(); // expected-note   {{Calling 'foo'}}
+         // expected-note@-1{{Returning from 'foo'}}
+
+  if (flag) // expected-note   {{Taking true branch}}
+            // expected-note@-1{{Assuming 'flag' is not equal to 0}}
+    *x = 5; // expected-warning{{Dereference of null pointer}}
+            // expected-note@-1{{Dereference of null pointer}}
+}
+} // end of namespace example_2
+
+namespace example_3 {
+int flag;
+bool coin();
+
+void foo() {
+  // TODO: It makes no sense at all for bar to have been assigned here.
+  flag = coin(); // expected-note {{Value assigned to 'flag'}}
+                 // expected-note@-1 {{Value assigned to 'bar'}}
+}
+
+int bar;
+
+void test() {
+  int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
+  flag = 1;
+
+  foo(); // expected-note   {{Calling 'foo'}}
+         // expected-note@-1{{Returning from 'foo'}}
+
+  if (bar) // expected-note   {{Taking true branch}}
+           // expected-note@-1{{Assuming 'bar' is not equal to 0}}
+    if (flag) // expected-note   {{Taking true branch}}
+              // expected-note@-1{{Assuming 'flag' is not equal to 0}}
+      *x = 5; // expected-warning{{Dereference of null pointer}}
+              // expected-note@-1{{Dereference of null pointer}}
+}
+} // end of namespace example_3
Index: clang/test/Analysis/diagnostics/undef-value-param.m
===================================================================
--- clang/test/Analysis/diagnostics/undef-value-param.m
+++ clang/test/Analysis/diagnostics/undef-value-param.m
@@ -52,7 +52,7 @@
 
 static void CreateRef(SCDynamicStoreRef *storeRef, unsigned x) {
     unsigned err = 0;
-    SCDynamicStoreRef ref = anotherCreateRef(&err, x);
+    SCDynamicStoreRef ref = anotherCreateRef(&err, x); // expected-note{{Value assigned to 'err'}}
     if (err) { 
                //expected-note@-1{{Assuming 'err' is not equal to 0}}
                //expected-note@-2{{Taking true branch}}
Index: clang/test/Analysis/diagnostics/no-store-func-path-notes.m
===================================================================
--- clang/test/Analysis/diagnostics/no-store-func-path-notes.m
+++ clang/test/Analysis/diagnostics/no-store-func-path-notes.m
@@ -16,17 +16,20 @@
     return 0;
   }
   return 1; // expected-note{{Returning without writing to '*var'}}
+            // expected-note@-1{{Returning the value 1}}
 }
 @end
 
 int foo(I *i) {
-  int x;                            //expected-note{{'x' declared without an initial value}}
-  int out = [i initVar:&x param:0]; //expected-note{{Calling 'initVar:param:'}}
-                                    //expected-note@-1{{Returning from 'initVar:param:'}}
-  if (out)                          //expected-note{{'out' is 1}}
-                                    //expected-note@-1{{Taking true branch}}
-    return x;                       //expected-warning{{Undefined or garbage value returned to caller}}
-                                    //expected-note@-1{{Undefined or garbage value returned to caller}}
+  int x;                            // expected-note{{'x' declared without an initial value}}
+  int out = [i initVar:&x param:0]; // expected-note{{Calling 'initVar:param:'}}
+                                    // expected-note@-1{{Returning from 'initVar:param:'}}
+                                    // expected-note@-2{{Passing the value 0 via 2nd parameter 'param'}}
+                                    // expected-note@-3{{'out' initialized to 1}}
+  if (out)                          // expected-note{{Taking true branch}}
+                                    // expected-note@-1{{'out' is 1}}
+    return x;                       // expected-warning{{Undefined or garbage value returned to caller}}
+                                    // expected-note@-1{{Undefined or garbage value returned to caller}}
   return 0;
 }
 
Index: clang/test/Analysis/diagnostics/Inputs/expected-plists/undef-value-param.m.plist
===================================================================
--- clang/test/Analysis/diagnostics/Inputs/expected-plists/undef-value-param.m.plist
+++ clang/test/Analysis/diagnostics/Inputs/expected-plists/undef-value-param.m.plist
@@ -137,6 +137,69 @@
            <key>file</key><integer>0</integer>
           </dict>
          </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>55</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>55</integer>
+           <key>col</key><integer>21</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>55</integer>
+      <key>col</key><integer>29</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>55</integer>
+         <key>col</key><integer>29</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>55</integer>
+         <key>col</key><integer>53</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>1</integer>
+     <key>extended_message</key>
+     <string>Value assigned to &apos;err&apos;</string>
+     <key>message</key>
+     <string>Value assigned to &apos;err&apos;</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>55</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>55</integer>
+           <key>col</key><integer>21</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
         <key>end</key>
          <array>
           <dict>
Index: clang/test/Analysis/Inputs/expected-plists/unix-fns.c.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/unix-fns.c.plist
+++ clang/test/Analysis/Inputs/expected-plists/unix-fns.c.plist
@@ -1593,6 +1593,35 @@
        </dict>
       </array>
     </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>223</integer>
+      <key>col</key><integer>24</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>223</integer>
+         <key>col</key><integer>24</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>227</integer>
+         <key>col</key><integer>3</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>&apos;q&apos; </string>
+     <key>message</key>
+     <string>&apos;q&apos; </string>
+    </dict>
     <dict>
      <key>kind</key><string>event</string>
      <key>location</key>
Index: clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist
+++ clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist
@@ -1883,6 +1883,35 @@
   <dict>
    <key>path</key>
    <array>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>439</integer>
+      <key>col</key><integer>3</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>439</integer>
+         <key>col</key><integer>3</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>439</integer>
+         <key>col</key><integer>16</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>&apos;date&apos; initialized here</string>
+     <key>message</key>
+     <string>&apos;date&apos; initialized here</string>
+    </dict>
     <dict>
      <key>kind</key><string>control</string>
      <key>edges</key>
@@ -9276,6 +9305,69 @@
            <key>file</key><integer>0</integer>
           </dict>
          </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>731</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>731</integer>
+           <key>col</key><integer>10</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>731</integer>
+      <key>col</key><integer>3</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>731</integer>
+         <key>col</key><integer>3</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>731</integer>
+         <key>col</key><integer>16</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>&apos;name&apos; initialized here</string>
+     <key>message</key>
+     <string>&apos;name&apos; initialized here</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>731</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>731</integer>
+           <key>col</key><integer>10</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
         <key>end</key>
          <array>
           <dict>
Index: clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist
+++ clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist
@@ -1883,6 +1883,35 @@
   <dict>
    <key>path</key>
    <array>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>439</integer>
+      <key>col</key><integer>3</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>439</integer>
+         <key>col</key><integer>3</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>439</integer>
+         <key>col</key><integer>16</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>&apos;date&apos; initialized here</string>
+     <key>message</key>
+     <string>&apos;date&apos; initialized here</string>
+    </dict>
     <dict>
      <key>kind</key><string>control</string>
      <key>edges</key>
@@ -9276,6 +9305,69 @@
            <key>file</key><integer>0</integer>
           </dict>
          </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>731</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>731</integer>
+           <key>col</key><integer>10</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>731</integer>
+      <key>col</key><integer>3</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>731</integer>
+         <key>col</key><integer>3</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>731</integer>
+         <key>col</key><integer>16</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>&apos;name&apos; initialized here</string>
+     <key>message</key>
+     <string>&apos;name&apos; initialized here</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>731</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>731</integer>
+           <key>col</key><integer>10</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
         <key>end</key>
          <array>
           <dict>
Index: clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
+++ clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
@@ -12057,6 +12057,35 @@
        </dict>
       </array>
     </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>459</integer>
+      <key>col</key><integer>5</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>459</integer>
+         <key>col</key><integer>5</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>459</integer>
+         <key>col</key><integer>13</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>The value 0 is assigned to &apos;first&apos;</string>
+     <key>message</key>
+     <string>The value 0 is assigned to &apos;first&apos;</string>
+    </dict>
     <dict>
      <key>kind</key><string>control</string>
      <key>edges</key>
Index: clang/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist
+++ clang/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist
@@ -677,6 +677,69 @@
            <key>file</key><integer>0</integer>
           </dict>
          </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>88</integer>
+           <key>col</key><integer>20</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>88</integer>
+           <key>col</key><integer>23</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>88</integer>
+      <key>col</key><integer>20</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>88</integer>
+         <key>col</key><integer>20</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>88</integer>
+         <key>col</key><integer>23</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Passing the value 1 via 1st parameter &apos;fail&apos;</string>
+     <key>message</key>
+     <string>Passing the value 1 via 1st parameter &apos;fail&apos;</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>88</integer>
+           <key>col</key><integer>20</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>88</integer>
+           <key>col</key><integer>23</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
         <key>end</key>
          <array>
           <dict>
Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1668,6 +1668,9 @@
   if (!LVNode)
     return false;
 
+  report.addVisitor(llvm::make_unique<TrackControlDependencyCondBRVisitor>(
+        InputNode));
+
   ProgramStateRef LVState = LVNode->getState();
 
   // The message send could be nil due to the receiver being nil.
@@ -1831,6 +1834,73 @@
   return std::make_shared<PathDiagnosticEventPiece>(L, OS.str());
 }
 
+//===----------------------------------------------------------------------===//
+// Implementation of TrackControlDependencyCondBRVisitor.
+//===----------------------------------------------------------------------===//
+
+TrackControlDependencyCondBRVisitor::TrackControlDependencyCondBRVisitor(
+    const ExplodedNode *O)
+  : Origin(O), ControlDepTree(&O->getCFG()) {}
+
+static CFGBlock *GetRelevantBlock(const ExplodedNode *Node) {
+  if (auto SP = Node->getLocationAs<StmtPoint>()) {
+    const Stmt *S = SP->getStmt();
+    assert(S);
+
+    return const_cast<CFGBlock *>(Node->getLocationContext()
+        ->getAnalysisDeclContext()->getCFGStmtMap()->getBlock(S));
+  }
+
+  return nullptr;
+}
+
+static const Expr *getTerminatorCondition(CFGBlock *B) {
+  // If the terminator is a temporary dtor or a virtual base, etc, we can't
+  // retrieve a meaningful condition, bail out.
+  if (B->rbegin()->getKind() != CFGElement::Kind::Statement)
+    return nullptr;
+
+  // This should be the condition of the terminator block.
+  const Stmt *S = B->rbegin()->castAs<CFGStmt>().getStmt();
+  assert(S);
+
+  if (const auto *Cond = dyn_cast<Expr>(S))
+    return Cond;
+
+  assert(isa<ObjCForCollectionStmt>(S) &&
+      "Only ObjCForCollectionStmt is known not to be a non-Expr terminator!");
+
+  // TODO: Return the collection.
+  return nullptr;
+}
+
+std::shared_ptr<PathDiagnosticPiece>
+TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N,
+                                               BugReporterContext &BRC,
+                                               BugReport &BR) {
+  // We can only reason about control dependencies within the same stack frame.
+  if (Origin->getStackFrame() != N->getStackFrame())
+    return nullptr;
+
+  CFGBlock *NB = GetRelevantBlock(N);
+
+  // Skip if we already inspected this block.
+  if (!VisitedBlocks.insert(NB).second)
+    return nullptr;
+
+  CFGBlock *OriginB = GetRelevantBlock(Origin);
+  if (!OriginB || !NB)
+    return nullptr;
+
+  if (ControlDepTree.isControlDependency(OriginB, NB))
+    if (const Expr *Condition = getTerminatorCondition(NB))
+      if (BR.addTrackedCondition(Condition))
+        bugreporter::trackExpressionValue(
+            N, Condition, BR, /*EnableNullFPSuppression=*/false);
+
+  return nullptr;
+}
+
 //===----------------------------------------------------------------------===//
 // Implementation of FindLastStoreBRVisitor.
 //===----------------------------------------------------------------------===//
Index: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
 
+#include "clang/Analysis/Analyses/Dominators.h"
 #include "clang/Analysis/ProgramPoint.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
@@ -159,6 +160,35 @@
   static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
 };
 
+/// Tracks the expressions that are a control dependency of the node that was
+/// supplied to the constructor.
+/// For example:
+///
+///   cond = 1;
+///   if (cond)
+///     10 / 0;
+///
+/// An error is emitted at line 3. This visitor realizes that the branch
+/// on line 2 is a control dependency of line 3, and tracks it's condition via
+/// trackExpressionValue().
+class TrackControlDependencyCondBRVisitor final : public BugReporterVisitor {
+  const ExplodedNode *Origin;
+  CFGControlDependencyTree ControlDepTree;
+  llvm::SmallSet<const CFGBlock *, 32> VisitedBlocks;
+
+public:
+  TrackControlDependencyCondBRVisitor(const ExplodedNode *O);
+
+  void Profile(llvm::FoldingSetNodeID &ID) const override {
+    static int x = 0;
+    ID.AddPointer(&x);
+  }
+
+  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
+                                                 BugReporterContext &BRC,
+                                                 BugReport &BR) override;
+};
+
 /// Visitor that tries to report interesting diagnostics from conditions.
 class ConditionBRVisitor final : public BugReporterVisitor {
   // FIXME: constexpr initialization isn't supported by MSVC2013.
Index: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -153,6 +153,9 @@
   /// \sa removeInvalidation
   llvm::SmallSet<InvalidationRecord, 4> Invalidations;
 
+  /// Conditions we're already tracking.
+  llvm::SmallPtrSet<const Expr *, 4> TrackedConditions;
+
 private:
   // Used internally by BugReporter.
   Symbols &getInterestingSymbols();
@@ -349,6 +352,10 @@
   visitor_iterator visitor_begin() { return Callbacks.begin(); }
   visitor_iterator visitor_end() { return Callbacks.end(); }
 
+  bool addTrackedCondition(const Expr *Cond) {
+    return TrackedConditions.insert(Cond).second;
+  }
+
   /// Profile to identify equivalent bug reports for error report coalescing.
   /// Reports are uniqued to ensure that we do not emit multiple diagnostics
   /// for each bug.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to