BugReporter:
- Group control flow and event PathDiagnosticPieces into PathDiagnosticMacroPieces.
- Afterwards, eliminate any PathDiagnosticMacroPieces from a PathDiagnostic that
  contain no informative events.

HTMLDiagnostics:
- Use new information about PathDiagnosticMacroPieces to specially format
  message bubbles for macro expansions containing interesting events.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66524 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 12e50d3..86ee484 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -563,6 +563,98 @@
 };
 }
 
+/// CompactPathDiagnostic - This function postprocesses a PathDiagnostic object
+///  and collapses PathDiagosticPieces that are expanded by macros.
+static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
+  typedef std::vector<std::pair<PathDiagnosticMacroPiece*, SourceLocation> >
+          MacroStackTy;
+  
+  typedef std::vector<PathDiagnosticPiece*>
+          PiecesTy;
+  
+  MacroStackTy MacroStack;
+  PiecesTy Pieces;
+  
+  for (PathDiagnostic::iterator I = PD.begin(), E = PD.end(); I!=E; ++I) {
+    // Get the location of the PathDiagnosticPiece.
+    const FullSourceLoc Loc = I->getLocation();    
+    
+    // Determine the instantiation location, which is the location we group
+    // related PathDiagnosticPieces.
+    SourceLocation InstantiationLoc = Loc.isMacroID() ? 
+                                      SM.getInstantiationLoc(Loc) :
+                                      SourceLocation();
+    
+    if (Loc.isFileID()) {
+      MacroStack.clear();
+      Pieces.push_back(&*I);
+      continue;
+    }
+
+    assert(Loc.isMacroID());
+    
+    // Is the PathDiagnosticPiece within the same macro group?
+    if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
+      MacroStack.back().first->push_back(&*I);
+      continue;
+    }
+
+    // We aren't in the same group.  Are we descending into a new macro
+    // or are part of an old one?
+    PathDiagnosticMacroPiece *MacroGroup = 0;
+
+    SourceLocation ParentInstantiationLoc = InstantiationLoc.isMacroID() ?
+                                          SM.getInstantiationLoc(Loc) :
+                                          SourceLocation();
+    
+    // Walk the entire macro stack.
+    while (!MacroStack.empty()) {
+      if (InstantiationLoc == MacroStack.back().second) {
+        MacroGroup = MacroStack.back().first;
+        break;
+      }
+      
+      if (ParentInstantiationLoc == MacroStack.back().second) {
+        MacroGroup = MacroStack.back().first;
+        break;
+      }
+      
+      MacroStack.pop_back();
+    }
+    
+    if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
+      // Create a new macro group and add it to the stack.
+      PathDiagnosticMacroPiece *NewGroup = new PathDiagnosticMacroPiece(Loc);
+
+      if (MacroGroup)
+        MacroGroup->push_back(NewGroup);
+      else {
+        assert(InstantiationLoc.isFileID());
+        Pieces.push_back(NewGroup);
+      }
+      
+      MacroGroup = NewGroup;
+      MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
+    }
+
+    // Finally, add the PathDiagnosticPiece to the group.
+    MacroGroup->push_back(&*I);
+  }
+  
+  // Now take the pieces and construct a new PathDiagnostic.
+  PD.resetPath(false);
+    
+  for (PiecesTy::iterator I=Pieces.begin(), E=Pieces.end(); I!=E; ++I) {
+    if (PathDiagnosticMacroPiece *MP=dyn_cast<PathDiagnosticMacroPiece>(*I))
+      if (!MP->containsEvent()) {
+        delete MP;
+        continue;
+      }
+    
+    PD.push_back(*I);
+  }
+}
+
 void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
                                            BugReportEquivClass& EQ) {
   
@@ -799,6 +891,10 @@
       getStateManager().iterBindings(N->getState(), SNS);
     }
   }
+  
+  // After constructing the full PathDiagnostic, do a pass over it to compact
+  // PathDiagnosticPieces that occur within a macro.
+  CompactPathDiagnostic(PD, getSourceManager());
 }