- Changed PathDiagnosticPiece::getLocation() to return a PathDiagnosticLocation
  instead of a FullSourceLoc. This resulted in a bunch of small edits in various
  clients.
- Updated BugReporter to include an alternate PathDiagnostic generation
  algorithm for PathDiagnosticClients desiring more control-flow pieces.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68193 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 1d1c2fa..f54200b 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -154,6 +154,14 @@
   
   PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S);
   
+  PathDiagnosticLocation
+  getEnclosingStmtLocation(const PathDiagnosticLocation &L) {
+    if (const Stmt *S = L.asStmt())
+      return getEnclosingStmtLocation(S);
+    
+    return L;
+  }
+  
   PathDiagnosticClient::PathGenerationScheme getGenerationScheme() const {
     return PDC ? PDC->getGenerationScheme() : PathDiagnosticClient::Extensive;
   }
@@ -196,13 +204,21 @@
 PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
   assert(S && "Null Stmt* passed to getEnclosingStmtLocation");
   ParentMap &P = getParentMap();
-  while (isa<Expr>(S)) {
+    
+  while (isa<DeclStmt>(S) || isa<Expr>(S)) {
     const Stmt *Parent = P.getParent(S);
     
     if (!Parent)
       break;
     
     switch (Parent->getStmtClass()) {
+      case Stmt::BinaryOperatorClass: {
+        const BinaryOperator *B = cast<BinaryOperator>(Parent);
+        if (B->isLogicalOp())
+          return PathDiagnosticLocation(S, SMgr);
+        break;
+      }
+        
       case Stmt::CompoundStmtClass:
       case Stmt::StmtExprClass:
         return PathDiagnosticLocation(S, SMgr);
@@ -674,7 +690,7 @@
               End = PDB.getEnclosingStmtLocation(S);
             
             PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                             "Loop condition is true.  Entering loop body"));
+                            "Loop condition is true.  Entering loop body"));
           }
           
           break;
@@ -688,10 +704,10 @@
           
           if (*(Src->succ_begin()+1) == Dst)
             PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                             "Taking false branch"));
+                                                        "Taking false branch"));
           else  
             PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                             "Taking true branch"));
+                                                         "Taking true branch"));
           
           break;
         }
@@ -715,6 +731,151 @@
 }
 
 //===----------------------------------------------------------------------===//
+// "Extensive" PathDiagnostic generation.
+//===----------------------------------------------------------------------===//
+
+static bool IsControlFlowExpr(const Stmt *S) {
+  const Expr *E = dyn_cast<Expr>(S);
+
+  if (!E)
+    return false;
+  
+  E = E->IgnoreParenCasts();  
+  
+  if (isa<ConditionalOperator>(E))
+    return true;
+  
+  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E))
+    if (B->isLogicalOp())
+      return true;
+  
+  return false;  
+}
+
+static void GenExtAddEdge(PathDiagnostic& PD,
+                          PathDiagnosticBuilder &PDB,
+                          PathDiagnosticLocation NewLoc,
+                          PathDiagnosticLocation &PrevLoc,
+                          PathDiagnosticLocation UpdateLoc) {
+
+  if (const Stmt *S = NewLoc.asStmt()) {
+    if (IsControlFlowExpr(S))
+      return;    
+  }
+  
+  
+  if (!PrevLoc.isValid()) {
+    PrevLoc = NewLoc;
+    return;
+  }
+  
+  if (NewLoc == PrevLoc)
+    return;
+  
+  PD.push_front(new PathDiagnosticControlFlowPiece(NewLoc, PrevLoc));
+  PrevLoc = UpdateLoc;
+}
+
+static bool IsNestedDeclStmt(const Stmt *S, ParentMap &PM) {
+  const DeclStmt *DS = dyn_cast<DeclStmt>(S);
+
+  if (!DS)
+    return false;
+  
+  const Stmt *Parent = PM.getParent(DS);
+  if (!Parent)
+    return false;
+  
+  if (const ForStmt *FS = dyn_cast<ForStmt>(Parent))
+    return FS->getInit() == DS;
+
+  // FIXME: In the future IfStmt/WhileStmt may contain DeclStmts in their condition.
+//  if (const IfStmt *IF = dyn_cast<IfStmt>(Parent))
+//    return IF->getCond() == DS;
+//  
+//  if (const WhileStmt *WS = dyn_cast<WhileStmt>(Parent))
+//    return WS->getCond() == DS;
+  
+  return false;
+}
+
+static void GenExtAddEdge(PathDiagnostic& PD,
+                          PathDiagnosticBuilder &PDB,
+                          const PathDiagnosticLocation &NewLoc,
+                          PathDiagnosticLocation &PrevLoc) {  
+  GenExtAddEdge(PD, PDB, NewLoc, PrevLoc, NewLoc);
+}
+
+static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
+                                            PathDiagnosticBuilder &PDB,
+                                            const ExplodedNode<GRState> *N) {
+
+  SourceManager& SMgr = PDB.getSourceManager();
+  const ExplodedNode<GRState>* NextNode = N->pred_empty()  
+                                          ? NULL : *(N->pred_begin());
+
+  PathDiagnosticLocation PrevLoc;
+  
+  while (NextNode) {
+    N = NextNode;    
+    NextNode = GetPredecessorNode(N);    
+    ProgramPoint P = N->getLocation();
+    
+    // Block edges.
+    if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+      const CFGBlock &Blk = *BE->getSrc();
+      if (const Stmt *Term = Blk.getTerminator()) {
+        const Stmt *Cond = Blk.getTerminatorCondition();
+        
+        if (!Cond || !IsControlFlowExpr(Cond)) {
+          GenExtAddEdge(PD, PDB, PathDiagnosticLocation(Term, SMgr), PrevLoc);
+          continue;
+        }
+      }
+      
+      // Only handle blocks with more than 1 statement here, as the blocks
+      // with one statement are handled at BlockEntrances.
+      if (Blk.size() > 1) {
+        const Stmt *S = *Blk.rbegin();
+        
+        // We don't add control-flow edges for DeclStmt's that appear in
+        // the condition of if/while/for or are control-flow merge expressions.
+        if (!IsControlFlowExpr(S) && !IsNestedDeclStmt(S, PDB.getParentMap())) {
+          GenExtAddEdge(PD, PDB, PathDiagnosticLocation(S, SMgr), PrevLoc);
+        }
+      }
+
+      continue;
+    }
+    
+    if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
+      if (const Stmt* S = BE->getFirstStmt()) {        
+        if (!IsControlFlowExpr(S) && !IsNestedDeclStmt(S, PDB.getParentMap())) {
+          // Are we jumping with the same enclosing statement?
+          if (PrevLoc.isValid() && PDB.getEnclosingStmtLocation(S) ==
+                                   PDB.getEnclosingStmtLocation(PrevLoc)) {
+            continue;
+          }
+          
+          GenExtAddEdge(PD, PDB, PDB.getEnclosingStmtLocation(S), PrevLoc);
+        }
+      }
+      
+      continue;
+    }
+      
+    PathDiagnosticPiece* p =
+      PDB.getReport().VisitNode(N, NextNode, PDB.getGraph(),
+                                PDB.getBugReporter(), PDB.getNodeMapClosure());
+    
+    if (p) {
+      GenExtAddEdge(PD, PDB, p->getLocation(), PrevLoc);
+      PD.push_front(p);
+    }
+  }
+}
+    
+//===----------------------------------------------------------------------===//
 // Methods for BugType and subclasses.
 //===----------------------------------------------------------------------===//
 BugType::~BugType() {}
@@ -993,7 +1154,7 @@
   
   for (PathDiagnostic::iterator I = PD.begin(), E = PD.end(); I!=E; ++I) {
     // Get the location of the PathDiagnosticPiece.
-    const FullSourceLoc Loc = I->getLocation();    
+    const FullSourceLoc Loc = I->getLocation().asLocation();    
     
     // Determine the instantiation location, which is the location we group
     // related PathDiagnosticPieces.
@@ -1114,6 +1275,8 @@
   
   switch (PDB.getGenerationScheme()) {
     case PathDiagnosticClient::Extensive:
+      GenerateExtensivePathDiagnostic(PD,PDB, N);
+      break;
     case PathDiagnosticClient::Minimal:
       GenerateMinimalPathDiagnostic(PD, PDB, N);
       break;