PathDiagnosticClients now retain ownership of passed PathDiagnostics, requiring
them to not be stack-allocated.

HTMLDiagnostics now batches PathDiagnostics before emitting HTML in its dtor.
This is a workaround for a problem when we trampled the Preprocessor state
when highlighting macros (sometimes resulting in an assertion failure).


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50102 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Driver/HTMLDiagnostics.cpp b/Driver/HTMLDiagnostics.cpp
index 2f1b6e3..c850c05 100644
--- a/Driver/HTMLDiagnostics.cpp
+++ b/Driver/HTMLDiagnostics.cpp
@@ -39,18 +39,21 @@
   bool createdDir, noDir;
   Preprocessor* PP;
   PreprocessorFactory* PPF;
+  std::vector<const PathDiagnostic*> BatchedDiags;  
 public:
   HTMLDiagnostics(const std::string& prefix, Preprocessor* pp,
                   PreprocessorFactory* ppf);
 
-  virtual ~HTMLDiagnostics() {}
+  virtual ~HTMLDiagnostics();
   
-  virtual void HandlePathDiagnostic(const PathDiagnostic& D);
+  virtual void HandlePathDiagnostic(const PathDiagnostic* D);
   
   void HandlePiece(Rewriter& R, const PathDiagnosticPiece& P,
                    unsigned num, unsigned max);
   
   void HighlightRange(Rewriter& R, SourceRange Range);
+
+  void ReportDiag(const PathDiagnostic& D);
 };
   
 } // end anonymous namespace
@@ -75,11 +78,30 @@
 // Report processing.
 //===----------------------------------------------------------------------===//
 
-void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic& D) {
-
-  if (D.empty())
+void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
+  if (!D)
     return;
   
+  if (D->empty()) {
+    delete D;
+    return;
+  }
+  
+  BatchedDiags.push_back(D);
+}
+
+HTMLDiagnostics::~HTMLDiagnostics() {
+  
+  while (!BatchedDiags.empty()) {
+    const PathDiagnostic* D = BatchedDiags.back();
+    BatchedDiags.pop_back();
+    ReportDiag(*D);
+    delete D;
+  }  
+}
+
+void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) {
+  
   // Create the HTML directory if it is missing.
   
   if (!createdDir) {
@@ -127,7 +149,13 @@
   // for example.
   
   if (PP) html::SyntaxHighlight(R, FileID, *PP);
-  if (PPF) html::HighlightMacros(R, FileID, *PPF);
+
+  // FIXME: We eventually want to use PPF to create a fresh Preprocessor,
+  //  once we have worked out the bugs.
+  //
+  // if (PPF) html::HighlightMacros(R, FileID, *PPF);
+  //
+  if (PP) html::HighlightMacros(R, FileID, *PP);
   
   // Get the full directory name of the analyzed file.
 
diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h
index cfca94b..f9bd0fd 100644
--- a/include/clang/Analysis/PathDiagnostic.h
+++ b/include/clang/Analysis/PathDiagnostic.h
@@ -181,7 +181,7 @@
                                 const SourceRange *Ranges, 
                                 unsigned NumRanges);
     
-  virtual void HandlePathDiagnostic(const PathDiagnostic& D) = 0;
+  virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0;
 };
 
 } //end clang namespace
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 6b68d7f..be1c52d 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -382,52 +382,51 @@
   if (R.getBugType().isCached(R))
     return;
 
-  PathDiagnostic D(R.getName());  
-  GeneratePathDiagnostic(D, R);
+  llvm::OwningPtr<PathDiagnostic> D(new PathDiagnostic(R.getName()));
+  GeneratePathDiagnostic(*D.get(), R);
 
   // Emit a full diagnostic for the path if we have a PathDiagnosticClient.
   
-  if (PD && !D.empty()) { 
-    PD->HandlePathDiagnostic(D);
+  if (PD && !D->empty()) { 
+    PD->HandlePathDiagnostic(D.take());
     return;    
   }
   
   // We don't have a PathDiagnosticClient, but we can still emit a single
   // line diagnostic.  Determine the location.
   
-  FullSourceLoc L = D.empty() ? R.getLocation(Ctx.getSourceManager())
-                               : D.back()->getLocation();
+  FullSourceLoc L = D->empty() ? R.getLocation(Ctx.getSourceManager())
+                               : D->back()->getLocation();
   
   
   // Determine the range.
   
   const SourceRange *Beg, *End;
   
-  if (!D.empty()) {
-    Beg = D.back()->ranges_begin();
-    End = D.back()->ranges_end();
+  if (!D->empty()) {
+    Beg = D->back()->ranges_begin();
+    End = D->back()->ranges_end();
   }
   else  
     R.getRanges(Beg, End);
 
   if (PD) {
-    PathDiagnostic D(R.getName());
     PathDiagnosticPiece* piece = new PathDiagnosticPiece(L, R.getDescription());
 
     for ( ; Beg != End; ++Beg)
       piece->addRange(*Beg);
 
-    D.push_back(piece);    
-    PD->HandlePathDiagnostic(D);
+    D->push_back(piece);    
+    PD->HandlePathDiagnostic(D.take());
   }
   else {
     std::ostringstream os;  
     os << "[CHECKER] ";
     
-    if (D.empty())
+    if (D->empty())
       os << R.getDescription();
     else
-      os << D.back()->getString();
+      os << D->back()->getString();
     
     
     unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp
index e4228c7..28b76b3 100644
--- a/lib/Analysis/PathDiagnostic.cpp
+++ b/lib/Analysis/PathDiagnostic.cpp
@@ -31,7 +31,7 @@
   
   // Create a PathDiagnostic with a single piece.
   
-  PathDiagnostic D;
+  PathDiagnostic* D = new PathDiagnostic();
   
   // Ripped from TextDiagnostics::FormatDiagnostic.  Perhaps we should
   // centralize it somewhere?
@@ -68,7 +68,7 @@
     ++Ranges;
   }
   
-  D.push_front(P);
+  D->push_front(P);
 
   HandlePathDiagnostic(D);  
 }