Re-apply my diagnostics-capture patch for CIndex, with some tweaks to
try to address the msvc failures.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96624 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index 61e9210..5eddee4 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -27,6 +27,7 @@
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/System/Program.h"
+#include "llvm/System/Signals.h"
 
 // Needed to define L_TMPNAM on some systems.
 #include <cstdio>
@@ -907,10 +908,13 @@
 }
 
 extern "C" {
-CXIndex clang_createIndex(int excludeDeclarationsFromPCH) {
+CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
+                          int displayDiagnostics) {
   CIndexer *CIdxr = new CIndexer();
   if (excludeDeclarationsFromPCH)
     CIdxr->setOnlyLocalDecls();
+  if (displayDiagnostics)
+    CIdxr->setDisplayDiagnostics();
   return CIdxr;
 }
 
@@ -997,8 +1001,18 @@
 
     // FIXME: Until we have broader testing, just drop the entire AST if we
     // encountered an error.
-    if (NumErrors != Diags->getNumErrors())
+    if (NumErrors != Diags->getNumErrors()) {
+      if (CXXIdx->getDisplayDiagnostics()) {
+        for (ASTUnit::diag_iterator D = Unit->diag_begin(), 
+                                 DEnd = Unit->diag_end();
+             D != DEnd; ++D) {
+          CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOptions());
+          clang_displayDiagnostic(&Diag, stderr,
+                                  clang_defaultDiagnosticDisplayOptions());
+        }
+      }
       return 0;
+    }
 
     return Unit.take();
   }
@@ -1089,18 +1103,35 @@
                                           RemappedFiles.data(),
                                           RemappedFiles.size(),
                                           /*CaptureDiagnostics=*/true);
-  if (ATU)
-    ATU->unlinkTemporaryFile();
-
-  // FIXME: Currently we don't report diagnostics on invalid ASTs.
   if (ATU) {
     LoadSerializedDiagnostics(DiagnosticsFile, 
                               num_unsaved_files, unsaved_files,
                               ATU->getFileManager(),
                               ATU->getSourceManager(),
                               ATU->getDiagnostics());
+  } else if (CXXIdx->getDisplayDiagnostics()) {
+    // We failed to load the ASTUnit, but we can still deserialize the
+    // diagnostics and emit them.
+    FileManager FileMgr;
+    SourceManager SourceMgr;
+    // FIXME: Faked LangOpts!
+    LangOptions LangOpts;
+    llvm::SmallVector<StoredDiagnostic, 4> Diags;
+    LoadSerializedDiagnostics(DiagnosticsFile, 
+                              num_unsaved_files, unsaved_files,
+                              FileMgr, SourceMgr, Diags);
+    for (llvm::SmallVector<StoredDiagnostic, 4>::iterator D = Diags.begin(), 
+                                                       DEnd = Diags.end();
+         D != DEnd; ++D) {
+      CXStoredDiagnostic Diag(*D, LangOpts);
+      clang_displayDiagnostic(&Diag, stderr,
+                              clang_defaultDiagnosticDisplayOptions());
+    }
   }
 
+  if (ATU)
+    ATU->unlinkTemporaryFile();
+
   for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
     TemporaryFiles[i].eraseFromDisk();
 
@@ -1909,6 +1940,10 @@
   *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc());
 }
 
+void clang_enableStackTraces(void) {
+  llvm::sys::PrintStackTraceOnErrorSignal();
+}
+
 } // end: extern "C"
 
 //===----------------------------------------------------------------------===//
diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports
index 1c445b7..449bb95 100644
--- a/tools/CIndex/CIndex.exports
+++ b/tools/CIndex/CIndex.exports
@@ -5,12 +5,15 @@
 _clang_createIndex
 _clang_createTranslationUnit
 _clang_createTranslationUnitFromSourceFile
+_clang_defaultDiagnosticDisplayOptions
+_clang_displayDiagnostic
 _clang_disposeCodeCompleteResults
 _clang_disposeDiagnostic
 _clang_disposeIndex
 _clang_disposeString
 _clang_disposeTokens
 _clang_disposeTranslationUnit
+_clang_enableStackTraces
 _clang_equalCursors
 _clang_equalLocations
 _clang_getClangVersion
diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp
index 9e89463..08510f2 100644
--- a/tools/CIndex/CIndexCodeCompletion.cpp
+++ b/tools/CIndex/CIndexCodeCompletion.cpp
@@ -177,6 +177,9 @@
 /// \brief The CXCodeCompleteResults structure we allocate internally;
 /// the client only sees the initial CXCodeCompleteResults structure.
 struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
+  AllocatedCXCodeCompleteResults();
+  ~AllocatedCXCodeCompleteResults();
+  
   /// \brief The memory buffer from which we parsed the results. We
   /// retain this buffer because the completion strings point into it.
   llvm::MemoryBuffer *Buffer;
@@ -194,6 +197,16 @@
   FileManager FileMgr;
 };
 
+AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() 
+  : CXCodeCompleteResults(), Buffer(0) { }
+  
+AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
+  for (unsigned I = 0, N = NumResults; I != N; ++I)
+    delete (CodeCompletionString *)Results[I].CompletionString;
+  delete [] Results;
+  delete Buffer;
+}
+  
 CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
                                           const char *source_filename,
                                           int num_command_line_args,
@@ -368,15 +381,6 @@
 
   AllocatedCXCodeCompleteResults *Results
     = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
-
-  for (unsigned I = 0, N = Results->NumResults; I != N; ++I)
-    delete (CXCompletionString *)Results->Results[I].CompletionString;
-  delete [] Results->Results;
-
-  Results->Results = 0;
-  Results->NumResults = 0;
-  delete Results->Buffer;
-  Results->Buffer = 0;
   delete Results;
 }
 
diff --git a/tools/CIndex/CIndexDiagnostic.cpp b/tools/CIndex/CIndexDiagnostic.cpp
index 70676f0..07c1983 100644
--- a/tools/CIndex/CIndexDiagnostic.cpp
+++ b/tools/CIndex/CIndexDiagnostic.cpp
@@ -47,6 +47,81 @@
   delete Stored;
 }
 
+void clang_displayDiagnostic(CXDiagnostic Diagnostic, FILE *Out, 
+                             unsigned Options) {
+  if (!Diagnostic || !Out)
+    return;
+
+  CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
+
+  // Ignore diagnostics that should be ignored.
+  if (Severity == CXDiagnostic_Ignored)
+    return;
+
+  if (Options & CXDiagnostic_DisplaySourceLocation) {
+    // Print source location (file:line), along with optional column
+    // and source ranges.
+    CXFile File;
+    unsigned Line, Column;
+    clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic),
+                                   &File, &Line, &Column, 0);
+    if (File) {
+      CXString FName = clang_getFileName(File);
+      fprintf(Out, "%s:%d:", clang_getCString(FName), Line);
+      clang_disposeString(FName);
+      if (Options & CXDiagnostic_DisplayColumn)
+        fprintf(Out, "%d:", Column);
+
+      if (Options & CXDiagnostic_DisplaySourceRanges) {
+        unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
+        bool PrintedRange = false;
+        for (unsigned I = 0; I != N; ++I) {
+          CXFile StartFile, EndFile;
+          CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
+          
+          unsigned StartLine, StartColumn, EndLine, EndColumn;
+          clang_getInstantiationLocation(clang_getRangeStart(Range),
+                                         &StartFile, &StartLine, &StartColumn,
+                                         0);
+          clang_getInstantiationLocation(clang_getRangeEnd(Range),
+                                         &EndFile, &EndLine, &EndColumn, 0);
+          
+          if (StartFile != EndFile || StartFile != File)
+            continue;
+          
+          fprintf(Out, "{%d:%d-%d:%d}", StartLine, StartColumn, 
+                  EndLine, EndColumn);
+          PrintedRange = true;
+        }
+        if (PrintedRange)
+          fprintf(Out, ":");
+      }
+    }
+
+    fprintf(Out, " ");
+  }
+
+  /* Print warning/error/etc. */
+  switch (Severity) {
+  case CXDiagnostic_Ignored: assert(0 && "impossible"); break;
+  case CXDiagnostic_Note: fprintf(Out, "note: "); break;
+  case CXDiagnostic_Warning: fprintf(Out, "warning: "); break;
+  case CXDiagnostic_Error: fprintf(Out, "error: "); break;
+  case CXDiagnostic_Fatal: fprintf(Out, "fatal error: "); break;
+  }
+
+  CXString Text = clang_getDiagnosticSpelling(Diagnostic);
+  if (clang_getCString(Text))
+    fprintf(Out, "%s\n", clang_getCString(Text));
+  else
+    fprintf(Out, "<no diagnostic text>\n");
+  clang_disposeString(Text);
+}
+
+unsigned clang_defaultDiagnosticDisplayOptions() {
+  return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn;
+}
+
 enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
   CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
   if (!StoredDiag)
@@ -204,15 +279,18 @@
       Diags.push_back(StoredDiagnostic(Diagnostic::Fatal,
                             (Twine("could not remap from missing file ") +
                                    unsaved_files[I].Filename).str()));
+      delete F;
       return;
     }
 
     MemoryBuffer *Buffer
       = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents,
                            unsaved_files[I].Contents + unsaved_files[I].Length);
-    if (!Buffer)
+    if (!Buffer) {
+      delete F;
       return;
-
+    }
+    
     SourceMgr.overrideFileContents(File, Buffer);
   }
 
@@ -224,8 +302,9 @@
     StoredDiagnostic Stored = StoredDiagnostic::Deserialize(FileMgr, SourceMgr,
                                                             Memory, MemoryEnd);
     if (!Stored)
-      return;
+      break;
 
     Diags.push_back(Stored);
   }
+  delete F;
 }
diff --git a/tools/CIndex/CIndexer.h b/tools/CIndex/CIndexer.h
index d559f13..1fa3ca9 100644
--- a/tools/CIndex/CIndexer.h
+++ b/tools/CIndex/CIndexer.h
@@ -34,11 +34,14 @@
 class CIndexer {
   bool UseExternalASTGeneration;
   bool OnlyLocalDecls;
-  
+  bool DisplayDiagnostics;
+
   llvm::sys::Path ClangPath;
   
 public:
-  CIndexer() : UseExternalASTGeneration(false), OnlyLocalDecls(false) { }
+ CIndexer() 
+   : UseExternalASTGeneration(false), OnlyLocalDecls(false),
+     DisplayDiagnostics(false) { }
   
   /// \brief Whether we only want to see "local" declarations (that did not
   /// come from a previous precompiled header). If false, we want to see all
@@ -46,6 +49,11 @@
   bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
   void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; }
   
+  bool getDisplayDiagnostics() const { return DisplayDiagnostics; }
+  void setDisplayDiagnostics(bool Display = true) {
+    DisplayDiagnostics = Display;
+  }
+
   bool getUseExternalASTGeneration() const { return UseExternalASTGeneration; }
   void setUseExternalASTGeneration(bool Value) {
     UseExternalASTGeneration = Value;