BugReporter (extensive diagnostics): introduce the notion of a "dead"
location context.  This allows us to postpone the decision of whether
or not a context should add a control-flow piece to the diagnostics
when inspecting its subexpressions.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70545 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 18bbe45..dcc88fe 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -757,21 +757,33 @@
 }
 
 namespace {
+class VISIBILITY_HIDDEN ContextLocation : public PathDiagnosticLocation {
+  bool IsDead;
+public:
+  ContextLocation(const PathDiagnosticLocation &L, bool isdead = false)
+    : PathDiagnosticLocation(L), IsDead(isdead) {}
+  
+  void markDead() { IsDead = true; }  
+  bool isDead() const { return IsDead; }
+};
+  
 class VISIBILITY_HIDDEN EdgeBuilder {
-  std::vector<PathDiagnosticLocation> CLocs;
-  typedef std::vector<PathDiagnosticLocation>::iterator iterator;
+  std::vector<ContextLocation> CLocs;
+  typedef std::vector<ContextLocation>::iterator iterator;
   PathDiagnostic &PD;
   PathDiagnosticBuilder &PDB;
   PathDiagnosticLocation PrevLoc;
-
+  
+  bool IsConsumedExpr(const PathDiagnosticLocation &L);
+  
   bool containsLocation(const PathDiagnosticLocation &Container,
                         const PathDiagnosticLocation &Containee);
   
   PathDiagnosticLocation getContextLocation(const PathDiagnosticLocation &L);
   
   void popLocation() {
-    PathDiagnosticLocation L = CLocs.back();
-    if (L.asLocation().isFileID()) {
+    if (!CLocs.back().isDead() && CLocs.back().asLocation().isFileID()) {
+      PathDiagnosticLocation L = CLocs.back();
       
       if (const Stmt *S = L.asStmt()) {
         while (1) {
@@ -938,20 +950,30 @@
   const PathDiagnosticLocation &CLoc = getContextLocation(NewLoc);
 
   while (!CLocs.empty()) {
-    const PathDiagnosticLocation &TopContextLoc = CLocs.back();
+    ContextLocation &TopContextLoc = CLocs.back();
     
     // Is the top location context the same as the one for the new location?
     if (TopContextLoc == CLoc) {
-      if (alwaysAdd)
+      if (alwaysAdd) {
+        if (IsConsumedExpr(TopContextLoc))
+            TopContextLoc.markDead();
+
         rawAddEdge(NewLoc);
+      }
 
       return;
     }
 
     if (containsLocation(TopContextLoc, CLoc)) {
-      if (alwaysAdd)
+      if (alwaysAdd) {
         rawAddEdge(NewLoc);
-
+        
+        if (IsConsumedExpr(CLoc)) {
+          CLocs.push_back(ContextLocation(CLoc, true));
+          return;
+        }
+      }
+      
       CLocs.push_back(CLoc);
       return;      
     }
@@ -964,6 +986,13 @@
   rawAddEdge(NewLoc);
 }
 
+bool EdgeBuilder::IsConsumedExpr(const PathDiagnosticLocation &L) {
+  if (const Expr *X = dyn_cast_or_null<Expr>(L.asStmt()))
+    return PDB.getParentMap().isConsumedExpr(X) && !IsControlFlowExpr(X);
+  
+  return false;
+}
+  
 void EdgeBuilder::addContext(const Stmt *S) {
   if (!S)
     return;
@@ -1040,8 +1069,10 @@
 
     if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {      
       if (const Stmt* S = BE->getFirstStmt()) {
-       if (IsControlFlowExpr(S))
+       if (IsControlFlowExpr(S)) {
+         // Add the proper context for '&&', '||', and '?'.
          EB.addContext(S);
+       }
        else
          EB.addContext(PDB.getEnclosingStmtLocation(S).asStmt());
       }