Introduce serialization and deserialization of diagnostic information
so that CIndex can report diagnostics through the normal mechanisms
even when executing Clang in a separate process. This applies both
when performing code completion and when using ASTs as an intermediary
for clang_createTranslationUnitFromSourceFile().

The serialized format is not perfect at the moment, because it does
not encapsulate macro-instantiation information. Instead, it maps all
source locations back to the instantiation location. However, it does
maintain source-range and fix-it information. To get perfect fidelity
from the serialized format would require serializing a large chunk of
the source manager; at present, it isn't clear if this code will live
long enough for that to matter.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94740 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 19c740d..6b0fdb8 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -83,6 +83,23 @@
 }
 
 // Diagnostics
+namespace {
+  class BinaryDiagnosticSerializer : public DiagnosticClient {
+    llvm::raw_ostream &OS;
+    SourceManager *SourceMgr;
+  public:
+    explicit BinaryDiagnosticSerializer(llvm::raw_ostream &OS)
+      : OS(OS), SourceMgr(0) { }
+    
+    virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+                                  const DiagnosticInfo &Info);
+  };
+}
+
+void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel,
+                                                  const DiagnosticInfo &Info) {
+  Info.Serialize(DiagLevel, OS);
+}
 
 static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
                               unsigned argc, char **argv,
@@ -122,8 +139,23 @@
 
   // Create the diagnostic client for reporting errors or for
   // implementing -verify.
-  llvm::OwningPtr<DiagnosticClient> DiagClient(
-    new TextDiagnosticPrinter(llvm::errs(), Opts));
+  llvm::OwningPtr<DiagnosticClient> DiagClient;
+  if (Opts.BinaryOutput) {
+    if (llvm::sys::Program::ChangeStderrToBinary()) {
+      // We weren't able to set standard error to binary, which is a
+      // bit of a problem. So, just create a text diagnostic printer
+      // to complain about this problem, and pretend that the user
+      // didn't try to use binary output.
+      DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
+      Diags->setClient(DiagClient.take());
+      Diags->Report(diag::err_fe_stderr_binary);
+      return Diags.take();
+    } else {
+      DiagClient.reset(new BinaryDiagnosticSerializer(llvm::errs()));
+    }
+  } else {
+    DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
+  }
 
   // Chain in -verify checker, if requested.
   if (Opts.VerifyDiagnostics)
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 0bca475..06fc15b 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -220,6 +220,8 @@
     Res.push_back("-fcolor-diagnostics");
   if (Opts.VerifyDiagnostics)
     Res.push_back("-verify");
+  if (Opts.BinaryOutput)
+    Res.push_back("-fdiagnostics-binary");
   if (Opts.ShowOptionNames)
     Res.push_back("-fdiagnostics-show-option");
   if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) {
@@ -808,6 +810,7 @@
   Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option);
   Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
   Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
+  Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
   Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
                                     DiagnosticOptions::DefaultTabStop, Diags);
   if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {