[cfe-commits] r144269 - in /cfe/trunk: include/clang-c/ include/clang/Frontend/ lib/Frontend/ tools/c-index-test/ tools/libclang/

Ted Kremenek kremenek at apple.com
Thu Nov 10 00:43:13 PST 2011


Author: kremenek
Date: Thu Nov 10 02:43:12 2011
New Revision: 144269

URL: http://llvm.org/viewvc/llvm-project?rev=144269&view=rev
Log:
serialized diagnostics: implement full deserialization of clang diagnostics via the libclang API.

I've tested it on simple cases and it works.  Test cases to follow as well as a few tweaks.

Added:
    cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp
    cfe/trunk/tools/libclang/CXLoadedDiagnostic.h
Modified:
    cfe/trunk/include/clang-c/Index.h
    cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h
    cfe/trunk/lib/Frontend/SerializedDiagnosticPrinter.cpp
    cfe/trunk/tools/c-index-test/c-index-test.c
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/tools/libclang/CIndexDiagnostic.cpp
    cfe/trunk/tools/libclang/CIndexDiagnostic.h
    cfe/trunk/tools/libclang/CMakeLists.txt
    cfe/trunk/tools/libclang/CXSourceLocation.cpp
    cfe/trunk/tools/libclang/CXStoredDiagnostic.cpp
    cfe/trunk/tools/libclang/CXTranslationUnit.h
    cfe/trunk/tools/libclang/libclang.exports

Modified: cfe/trunk/include/clang-c/Index.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=144269&r1=144268&r2=144269&view=diff
==============================================================================
--- cfe/trunk/include/clang-c/Index.h (original)
+++ cfe/trunk/include/clang-c/Index.h Thu Nov 10 02:43:12 2011
@@ -522,6 +522,86 @@
 typedef void *CXDiagnostic;
 
 /**
+ * \brief A group of CXDiagnostics.
+ */
+typedef void *CXDiagnosticSet;
+  
+/**
+ * \brief Determine the number of diagnostics in a CXDiagnosticSet.
+ */
+CINDEX_LINKAGE unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags);
+
+/**
+ * \brief Retrieve a diagnostic associated with the given CXDiagnosticSet.
+ *
+ * \param Unit the CXDiagnosticSet to query.
+ * \param Index the zero-based diagnostic number to retrieve.
+ *
+ * \returns the requested diagnostic. This diagnostic must be freed
+ * via a call to \c clang_disposeDiagnostic().
+ */
+CINDEX_LINKAGE CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
+                                                     unsigned Index);  
+
+
+/**
+ * \brief Describes the kind of error that occurred (if any) in a call to
+ * \c clang_loadDiagnostics.
+ */
+enum CXLoadDiag_Error {
+  /**
+   * \brief Indicates that no error occurred.
+   */
+  CXLoadDiag_None = 0,
+  
+  /**
+   * \brief Indicates that an unknown error occurred while attempting to
+   * deserialize diagnostics.
+   */
+  CXLoadDiag_Unknown = 1,
+  
+  /**
+   * \brief Indicates that the file containing the serialized diagnostics
+   * could not be opened.
+   */
+  CXLoadDiag_CannotLoad = 2,
+  
+  /**
+   * \brief Indicates that the serialized diagnostics file is invalid or
+   *  corrupt.
+   */
+  CXLoadDiag_InvalidFile = 3
+};
+  
+/**
+ * \brief Deserialize a set of diagnostics from a Clang diagnostics bitcode
+ *  file.
+ *
+ * \param The name of the file to deserialize.
+ * \param A pointer to a enum value recording if there was a problem
+ *        deserializing the diagnostics.
+ * \param A pointer to a CXString for recording the error string
+ *        if the file was not successfully loaded.
+ *
+ * \returns A loaded CXDiagnosticSet if successful, and NULL otherwise.  These
+ *  diagnostics should be released using clang_disposeDiagnosticSet().
+ */
+CINDEX_LINKAGE CXDiagnosticSet clang_loadDiagnostics(const char *file,
+                                                  enum CXLoadDiag_Error *error,
+                                                  CXString *errorString);
+
+/**
+ * \brief Release a CXDiagnosticSet and all of its contained diagnostics.
+ */
+CINDEX_LINKAGE void clang_disposeDiagnosticSet(CXDiagnosticSet Diags);
+
+/**
+ * \brief Retrieve the child diagnostics of a CXDiagnostic.  This
+ *  CXDiagnosticSet does not need to be released by clang_diposeDiagnosticSet.
+ */
+CINDEX_LINKAGE CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D);
+
+/**
  * \brief Determine the number of diagnostics produced for the given
  * translation unit.
  */

Modified: cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h?rev=144269&r1=144268&r2=144269&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h (original)
+++ cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h Thu Nov 10 02:43:12 2011
@@ -39,7 +39,9 @@
   RECORD_DIAG_FLAG,
   RECORD_CATEGORY,
   RECORD_FILENAME,
-  RECORD_FIXIT
+  RECORD_FIXIT,
+  RECORD_FIRST = RECORD_VERSION,
+  RECORD_LAST = RECORD_FIXIT
 };
 
 /// \brief Returns a DiagnosticConsumer that serializes diagnostics to

Modified: cfe/trunk/lib/Frontend/SerializedDiagnosticPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/SerializedDiagnosticPrinter.cpp?rev=144269&r1=144268&r2=144269&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/SerializedDiagnosticPrinter.cpp (original)
+++ cfe/trunk/lib/Frontend/SerializedDiagnosticPrinter.cpp Thu Nov 10 02:43:12 2011
@@ -16,6 +16,7 @@
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/Version.h"
+#include "clang/Lex/Lexer.h"
 #include "clang/Frontend/SerializedDiagnosticPrinter.h"
 
 using namespace clang;
@@ -47,7 +48,8 @@
 class SDiagsWriter : public DiagnosticConsumer {
 public:  
   SDiagsWriter(DiagnosticsEngine &diags, llvm::raw_ostream *os) 
-    : Stream(Buffer), OS(os), Diags(diags), inNonNoteDiagnostic(false)
+    : LangOpts(0), Stream(Buffer), OS(os), Diags(diags),
+      inNonNoteDiagnostic(false)
   { 
     EmitPreamble();
   };
@@ -59,6 +61,11 @@
   
   void EndSourceFile();
   
+  void BeginSourceFile(const LangOptions &LO,
+                       const Preprocessor *PP) {
+    LangOpts = &LO;
+  }
+  
   DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
     // It makes no sense to clone this.
     return 0;
@@ -88,7 +95,8 @@
   unsigned getEmitFile(SourceLocation Loc);
   
   /// \brief Add SourceLocation information the specified record.
-  void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record);
+  void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
+                      unsigned TokSize = 0);
 
   /// \brief Add CharSourceRange information the specified record.
   void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record);
@@ -96,6 +104,8 @@
   /// \brief The version of the diagnostics file.
   enum { Version = 1 };
 
+  const LangOptions *LangOpts;
+  
   /// \brief The byte buffer for the serialized content.
   std::vector<unsigned char> Buffer;
 
@@ -181,13 +191,14 @@
 }
 
 void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
-                                  RecordDataImpl &Record) {
+                                  RecordDataImpl &Record,
+                                  unsigned TokSize) {
   if (Loc.isInvalid()) {
     // Emit a "sentinel" location.
-    Record.push_back((unsigned) 0); // File.
-    Record.push_back(~(unsigned)0); // Line.
-    Record.push_back(~(unsigned)0); // Column.
-    Record.push_back(~(unsigned)0); // Offset.
+    Record.push_back((unsigned)0); // File.
+    Record.push_back((unsigned)0); // Line.
+    Record.push_back((unsigned)0); // Column.
+    Record.push_back((unsigned)0); // Offset.
     return;
   }
 
@@ -195,7 +206,7 @@
   Loc = SM.getSpellingLoc(Loc);
   Record.push_back(getEmitFile(Loc));
   Record.push_back(SM.getSpellingLineNumber(Loc));
-  Record.push_back(SM.getSpellingColumnNumber(Loc));
+  Record.push_back(SM.getSpellingColumnNumber(Loc)+TokSize);
   
   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
   FileID FID = LocInfo.first;
@@ -206,7 +217,13 @@
 void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
                                               RecordDataImpl &Record) {
   AddLocToRecord(Range.getBegin(), Record);
-  AddLocToRecord(Range.getEnd(), Record);
+  unsigned TokSize = 0;
+  if (Range.isTokenRange())
+    TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
+                                        Diags.getSourceManager(),
+                                        *LangOpts);
+  
+  AddLocToRecord(Range.getEnd(), Record, TokSize);
 }
 
 unsigned SDiagsWriter::getEmitFile(SourceLocation Loc) {

Modified: cfe/trunk/tools/c-index-test/c-index-test.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/c-index-test/c-index-test.c?rev=144269&r1=144268&r2=144269&view=diff
==============================================================================
--- cfe/trunk/tools/c-index-test/c-index-test.c (original)
+++ cfe/trunk/tools/c-index-test/c-index-test.c Thu Nov 10 02:43:12 2011
@@ -2431,6 +2431,155 @@
 }
 
 /******************************************************************************/
+/* Serialized diagnostics.                                                    */
+/******************************************************************************/
+
+static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error) {
+  switch (error) {
+    case CXLoadDiag_CannotLoad: return "Cannot Load File";
+    case CXLoadDiag_None: break;
+    case CXLoadDiag_Unknown: return "Unknown";
+    case CXLoadDiag_InvalidFile: return "Invalid File";
+  }
+  return "None";
+}
+
+static const char *getSeverityString(enum CXDiagnosticSeverity severity) {
+  switch (severity) {
+    case CXDiagnostic_Note: return "note";
+    case CXDiagnostic_Error: return "error";
+    case CXDiagnostic_Fatal: return "fatal";
+    case CXDiagnostic_Ignored: return "ignored";
+    case CXDiagnostic_Warning: return "warning";
+  }
+  return "unknown";
+}
+
+static void printIndent(unsigned indent) {
+  while (indent > 0) {
+    fprintf(stderr, " ");
+    --indent;
+  }
+}
+
+static void printLocation(CXSourceLocation L) {
+  CXFile File;
+  CXString FileName;
+  unsigned line, column, offset;
+  
+  clang_getExpansionLocation(L, &File, &line, &column, &offset);
+  FileName = clang_getFileName(File);
+  
+  fprintf(stderr, "%s:%d:%d", clang_getCString(FileName), line, column);
+  clang_disposeString(FileName);
+}
+
+static void printRanges(CXDiagnostic D, unsigned indent) {
+  unsigned i, n = clang_getDiagnosticNumRanges(D);
+  
+  for (i = 0; i < n; ++i) {
+    CXSourceLocation Start, End;
+    CXSourceRange SR = clang_getDiagnosticRange(D, i);
+    Start = clang_getRangeStart(SR);
+    End = clang_getRangeEnd(SR);
+    
+    printIndent(indent);
+    fprintf(stderr, "Range: ");
+    printLocation(Start);
+    fprintf(stderr, " ");
+    printLocation(End);
+    fprintf(stderr, "\n");
+  }
+}
+
+static void printFixIts(CXDiagnostic D, unsigned indent) {
+  unsigned i, n = clang_getDiagnosticNumFixIts(D);
+  for (i = 0 ; i < n; ++i) {
+    CXSourceRange ReplacementRange;
+    CXString text;
+    text = clang_getDiagnosticFixIt(D, i, &ReplacementRange);
+    
+    printIndent(indent);
+    fprintf(stderr, "FIXIT: (");
+    printLocation(clang_getRangeStart(ReplacementRange));
+    fprintf(stderr, " - ");
+    printLocation(clang_getRangeEnd(ReplacementRange));
+    fprintf(stderr, "): \"%s\"\n", clang_getCString(text));
+    clang_disposeString(text);
+  }  
+}
+
+static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
+  if (!Diags)
+    return;
+  
+  fprintf(stderr, "\n");
+
+  unsigned i = 0;
+  unsigned n = clang_getNumDiagnosticsInSet(Diags);
+  for (i = 0; i < n; ++i) {
+    CXSourceLocation DiagLoc;
+    CXDiagnostic D;
+    CXFile File;
+    CXString FileName, DiagSpelling, DiagOption;
+    unsigned line, column, offset;
+    const char *DiagOptionStr = 0;
+    
+    D = clang_getDiagnosticInSet(Diags, i);
+    DiagLoc = clang_getDiagnosticLocation(D);
+    clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset);
+    FileName = clang_getFileName(File);
+    DiagSpelling = clang_getDiagnosticSpelling(D);
+    
+    printIndent(indent);
+    
+    fprintf(stderr, "%s:%d:%d: %s: %s",
+            clang_getCString(FileName),
+            line,
+            column,
+            getSeverityString(clang_getDiagnosticSeverity(D)),
+            clang_getCString(DiagSpelling));
+
+    DiagOption = clang_getDiagnosticOption(D, 0);
+    DiagOptionStr = clang_getCString(DiagOption);
+    if (DiagOptionStr) {
+      fprintf(stderr, " [%s]", DiagOptionStr);
+    }
+    
+    fprintf(stderr, "\n");
+    
+    printRanges(D, indent);
+    printFixIts(D, indent);
+    
+    // Print subdiagnostics.
+    printDiagnosticSet(clang_getChildDiagnostics(D), indent+2);
+
+    clang_disposeString(FileName);
+    clang_disposeString(DiagSpelling);
+    clang_disposeString(DiagOption);
+  }  
+}
+
+static int read_diagnostics(const char *filename) {
+  enum CXLoadDiag_Error error;
+  CXString errorString;
+  CXDiagnosticSet Diags = 0;
+  
+  Diags = clang_loadDiagnostics(filename, &error, &errorString);
+  if (!Diags) {
+    fprintf(stderr, "Trouble deserializing file (%s): %s\n",
+            getDiagnosticCodeStr(error),
+            clang_getCString(errorString));
+    clang_disposeString(errorString);
+    return 1;
+  }
+  
+  printDiagnosticSet(Diags, 0);
+  clang_disposeDiagnosticSet(Diags);
+  return 0;
+}
+
+/******************************************************************************/
 /* Command line processing.                                                   */
 /******************************************************************************/
 
@@ -2475,7 +2624,9 @@
     "       c-index-test -test-print-typekind {<args>}*\n"
     "       c-index-test -print-usr [<CursorKind> {<args>}]*\n"
     "       c-index-test -print-usr-file <file>\n"
-    "       c-index-test -write-pch <file> <compiler arguments>\n\n");
+    "       c-index-test -write-pch <file> <compiler arguments>\n");
+  fprintf(stderr,
+    "       c-index-test -read-diagnostics <file>\n\n");
   fprintf(stderr,
     " <symbol filter> values:\n%s",
     "   all - load all symbols, including those from PCH\n"
@@ -2492,6 +2643,8 @@
 
 int cindextest_main(int argc, const char **argv) {
   clang_enableStackTraces();
+  if (argc > 2 && strcmp(argv[1], "-read-diagnostics") == 0)
+      return read_diagnostics(argv[2]);
   if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
     return perform_code_completion(argc, argv, 0);
   if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1])

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=144269&r1=144268&r2=144269&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Thu Nov 10 02:43:12 2011
@@ -58,6 +58,7 @@
   CXTranslationUnit D = new CXTranslationUnitImpl();
   D->TUData = TU;
   D->StringPool = createCXStringPool();
+  D->Diagnostics = 0;
   return D;
 }
 
@@ -2562,6 +2563,7 @@
 
     delete static_cast<ASTUnit *>(CTUnit->TUData);
     disposeCXStringPool(CTUnit->StringPool);
+    delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics);
     delete CTUnit;
   }
 }
@@ -2582,6 +2584,11 @@
   ReparseTranslationUnitInfo *RTUI =
     static_cast<ReparseTranslationUnitInfo*>(UserData);
   CXTranslationUnit TU = RTUI->TU;
+
+  // Reset the associated diagnostics.
+  delete static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
+  TU->Diagnostics = 0;
+
   unsigned num_unsaved_files = RTUI->num_unsaved_files;
   struct CXUnsavedFile *unsaved_files = RTUI->unsaved_files;
   unsigned options = RTUI->options;

Modified: cfe/trunk/tools/libclang/CIndexDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndexDiagnostic.cpp?rev=144269&r1=144268&r2=144269&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndexDiagnostic.cpp (original)
+++ cfe/trunk/tools/libclang/CIndexDiagnostic.cpp Thu Nov 10 02:43:12 2011
@@ -28,27 +28,58 @@
 using namespace clang::cxstring;
 using namespace llvm;
 
+
+CXDiagnosticSetImpl::~CXDiagnosticSetImpl() {
+  for (std::vector<CXDiagnosticImpl *>::iterator it = Diagnostics.begin(),
+       et = Diagnostics.end();
+       it != et; ++it) {
+    delete *it;
+  }
+}
+
+CXDiagnosticImpl::~CXDiagnosticImpl() {}
+
+static CXDiagnosticSetImpl *lazyCreateDiags(CXTranslationUnit TU) {
+  if (!TU->Diagnostics) {
+    ASTUnit *AU = static_cast<ASTUnit *>(TU->TUData);
+    CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
+    TU->Diagnostics = Set;
+    
+    for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
+         ei = AU->stored_diag_end(); it != ei; ++it) {
+      CXStoredDiagnostic *D =
+        new CXStoredDiagnostic(*it, AU->getASTContext().getLangOptions());
+      Set->appendDiagnostic(D);
+    }
+  }
+  return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
+}
+
 //-----------------------------------------------------------------------------
 // C Interface Routines
 //-----------------------------------------------------------------------------
 extern "C" {
 
 unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
-  ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData);
-  return CXXUnit? CXXUnit->stored_diag_size() : 0;
+  if (!Unit->TUData)
+    return 0;
+  return lazyCreateDiags(Unit)->getNumDiagnostics();
 }
 
 CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
-  ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData);
-  if (!CXXUnit || Index >= CXXUnit->stored_diag_size())
+  if (!Unit->TUData)
+    return 0;
+
+  CXDiagnosticSetImpl *Diags = lazyCreateDiags(Unit);
+  if (Index >= Diags->getNumDiagnostics())
     return 0;
 
-  return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index],
-                                CXXUnit->getASTContext().getLangOptions());
+  return Diags->getDiagnostic(Index);
 }
 
 void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
-  delete static_cast<CXDiagnosticImpl *>(Diagnostic);
+  // No-op.  Kept as a legacy API.  CXDiagnostics are now managed
+  // by the enclosing CXDiagnosticSet.
 }
 
 CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
@@ -243,4 +274,32 @@
   return D->getFixIt(FixIt, ReplacementRange);
 }
 
+void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) {
+  CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags);
+  if (D->isExternallyManaged())
+    delete D;
+}
+  
+CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
+                                      unsigned Index) {
+  if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
+    if (Index < D->getNumDiagnostics())
+      return D->getDiagnostic(Index);
+  return 0;  
+}
+  
+CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) {
+  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) {
+    CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics();
+    return ChildDiags.empty() ? 0 : (CXDiagnosticSet) &ChildDiags;
+  }
+  return 0;
+}
+
+unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {
+  if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
+    return D->getNumDiagnostics();
+  return 0;
+}
+
 } // end extern "C"

Modified: cfe/trunk/tools/libclang/CIndexDiagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndexDiagnostic.h?rev=144269&r1=144268&r2=144269&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndexDiagnostic.h (original)
+++ cfe/trunk/tools/libclang/CIndexDiagnostic.h Thu Nov 10 02:43:12 2011
@@ -14,15 +14,47 @@
 #define LLVM_CLANG_CINDEX_DIAGNOSTIC_H
 
 #include "clang-c/Index.h"
+#include <vector>
+#include <assert.h>
 
 namespace clang {
 
 class LangOptions;
 class StoredDiagnostic;
+class CXDiagnosticImpl;
+  
+class CXDiagnosticSetImpl {
+  std::vector<CXDiagnosticImpl *> Diagnostics;
+  const bool IsExternallyManaged;
+public:
+  CXDiagnosticSetImpl(bool isManaged = false)
+    : IsExternallyManaged(isManaged) {}
+
+  virtual ~CXDiagnosticSetImpl();
+  
+  size_t getNumDiagnostics() const {
+    return Diagnostics.size();
+  }
+  
+  CXDiagnosticImpl *getDiagnostic(unsigned i) const {
+    assert(i < getNumDiagnostics());
+    return Diagnostics[i];
+  }
+  
+  void appendDiagnostic(CXDiagnosticImpl *D) {
+    Diagnostics.push_back(D);
+  }
+  
+  bool empty() const {
+    return Diagnostics.empty();
+  }
+  
+  bool isExternallyManaged() const { return IsExternallyManaged; }
+};
 
 class CXDiagnosticImpl {
 public:
-  enum Kind { StoredDiagnosticKind, SerializedDiagnosticKind };
+  enum Kind { StoredDiagnosticKind, LoadedDiagnosticKind };
   
   virtual ~CXDiagnosticImpl();
   
@@ -55,9 +87,18 @@
                             CXSourceRange *ReplacementRange) const = 0;
 
   Kind getKind() const { return K; }
-
+  
+  CXDiagnosticSetImpl &getChildDiagnostics() {
+    return ChildDiags;
+  }
+  
 protected:
   CXDiagnosticImpl(Kind k) : K(k) {}
+  CXDiagnosticSetImpl ChildDiags;
+  
+  void append(CXDiagnosticImpl *D) {
+    ChildDiags.appendDiagnostic(D);
+  }
   
 private:
   Kind K;

Modified: cfe/trunk/tools/libclang/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CMakeLists.txt?rev=144269&r1=144268&r2=144269&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CMakeLists.txt (original)
+++ cfe/trunk/tools/libclang/CMakeLists.txt Thu Nov 10 02:43:12 2011
@@ -29,6 +29,8 @@
   CIndexer.h
   CXCursor.cpp
   CXCursor.h
+  CXLoadedDiagnostic.cpp
+  CXLoadedDiagnostic.h
   CXSourceLocation.cpp
   CXSourceLocation.h
   CXStoredDiagnostic.cpp

Added: cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp?rev=144269&view=auto
==============================================================================
--- cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp (added)
+++ cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp Thu Nov 10 02:43:12 2011
@@ -0,0 +1,655 @@
+/*===-- CXLoadedDiagnostic.cpp - Handling of persisent diags -*- C++ -*-===*\
+|*                                                                            *|
+|*                     The LLVM Compiler Infrastructure                       *|
+|*                                                                            *|
+|* This file is distributed under the University of Illinois Open Source      *|
+|* License. See LICENSE.TXT for details.                                      *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*|
+|*                                                                            *|
+|* Implements handling of persisent diagnostics.                              *|
+|*                                                                            *|
+\*===----------------------------------------------------------------------===*/
+
+#include "CXLoadedDiagnostic.h"
+#include "CXString.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/SerializedDiagnosticPrinter.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/Optional.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <assert.h>
+
+using namespace clang;
+using namespace clang::cxstring;
+
+//===----------------------------------------------------------------------===//
+// Extend CXDiagnosticSetImpl which contains strings for diagnostics.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::DenseMap<unsigned, llvm::StringRef> Strings;
+
+namespace {
+class CXLoadedDiagnosticSetImpl : public CXDiagnosticSetImpl {
+public:
+  CXLoadedDiagnosticSetImpl() : CXDiagnosticSetImpl(true), FakeFiles(FO) {}
+  virtual ~CXLoadedDiagnosticSetImpl() {}  
+
+  llvm::StringRef makeString(const char *blob, unsigned blobLen);
+  
+  llvm::BumpPtrAllocator Alloc;
+  Strings Categories;
+  Strings WarningFlags;
+  Strings FileNames;
+  
+  FileSystemOptions FO;
+  FileManager FakeFiles;
+  llvm::DenseMap<unsigned, const FileEntry *> Files;
+};
+}
+
+llvm::StringRef CXLoadedDiagnosticSetImpl::makeString(const char *blob,
+                                                      unsigned bloblen) {
+  char *mem = Alloc.Allocate<char>(bloblen);
+  memcpy(mem, blob, bloblen);
+  return llvm::StringRef(mem, bloblen);
+}
+
+//===----------------------------------------------------------------------===//
+// Cleanup.
+//===----------------------------------------------------------------------===//
+
+CXLoadedDiagnostic::~CXLoadedDiagnostic() {}
+
+//===----------------------------------------------------------------------===//
+// Public CXLoadedDiagnostic methods.
+//===----------------------------------------------------------------------===//
+
+CXDiagnosticSeverity CXLoadedDiagnostic::getSeverity() const {
+  // FIXME: possibly refactor with logic in CXStoredDiagnostic.
+  switch (severity) {
+    case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored;
+    case DiagnosticsEngine::Note:    return CXDiagnostic_Note;
+    case DiagnosticsEngine::Warning: return CXDiagnostic_Warning;
+    case DiagnosticsEngine::Error:   return CXDiagnostic_Error;
+    case DiagnosticsEngine::Fatal:   return CXDiagnostic_Fatal;
+  }
+  
+  llvm_unreachable("Invalid diagnostic level");
+  return CXDiagnostic_Ignored;
+}
+
+static CXSourceLocation makeLocation(const CXLoadedDiagnostic::Location *DLoc) {
+  // The lowest bit of ptr_data[0] is always set to 1 to indicate this
+  // is a persistent diagnostic.
+  uintptr_t V = (uintptr_t) DLoc;
+  V |= 0x1;
+  CXSourceLocation Loc = { {  (void*) V, 0 }, 0 };
+  return Loc;
+}  
+
+CXSourceLocation CXLoadedDiagnostic::getLocation() const {
+  // The lowest bit of ptr_data[0] is always set to 1 to indicate this
+  // is a persistent diagnostic.
+  return makeLocation(&DiagLoc);
+}
+
+CXString CXLoadedDiagnostic::getSpelling() const {
+  return cxstring::createCXString(Spelling, false);  
+}
+
+CXString CXLoadedDiagnostic::getDiagnosticOption(CXString *Disable) const {
+  if (DiagOption.empty())
+    return createCXString("");
+
+  // FIXME: possibly refactor with logic in CXStoredDiagnostic.
+  if (Disable)
+    *Disable = createCXString((Twine("-Wno-") + DiagOption).str());
+  return createCXString((Twine("-W") + DiagOption).str());
+}
+
+unsigned CXLoadedDiagnostic::getCategory() const {
+  return category;
+}
+
+unsigned CXLoadedDiagnostic::getNumRanges() const {
+  return Ranges.size();
+}
+
+CXSourceRange CXLoadedDiagnostic::getRange(unsigned Range) const {
+  assert(Range < Ranges.size());
+  return Ranges[Range];
+}
+
+unsigned CXLoadedDiagnostic::getNumFixIts() const {
+  return FixIts.size();
+}
+
+CXString CXLoadedDiagnostic::getFixIt(unsigned FixIt,
+                                      CXSourceRange *ReplacementRange) const {
+  assert(FixIt < FixIts.size());
+  if (ReplacementRange)
+    *ReplacementRange = FixIts[FixIt].first;
+  return FixIts[FixIt].second;
+}
+
+void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location,
+                                        CXFile *file,
+                                        unsigned int *line,
+                                        unsigned int *column,
+                                        unsigned int *offset) {
+  
+  
+  // CXSourceLocation consists of the following fields:
+  //
+  //   void *ptr_data[2];
+  //   unsigned int_data;
+  //
+  // The lowest bit of ptr_data[0] is always set to 1 to indicate this
+  // is a persistent diagnostic.
+  //
+  // For now, do the unoptimized approach and store the data in a side
+  // data structure.  We can optimize this case later.
+  
+  uintptr_t V = (uintptr_t) location.ptr_data[0];
+  assert((V & 0x1) == 1);
+  V &= ~(uintptr_t)1;
+  
+  const Location &Loc = *((Location*)V);
+  
+  if (file)
+    *file = Loc.file;  
+  if (line)
+    *line = Loc.line;
+  if (column)
+    *column = Loc.column;
+  if (offset)
+    *offset = Loc.offset;
+}
+
+//===----------------------------------------------------------------------===//
+// Deserialize diagnostics.
+//===----------------------------------------------------------------------===//
+
+enum { MaxSupportedVersion = 1 };
+typedef SmallVector<uint64_t, 64> RecordData;
+enum LoadResult { Failure = 1, Success = 0 };
+enum StreamResult { Read_EndOfStream,
+                    Read_BlockBegin,
+                    Read_Failure,
+                    Read_Record,
+                    Read_BlockEnd };
+
+namespace {
+class DiagLoader {
+  enum CXLoadDiag_Error *error;
+  CXString *errorString;
+  
+  void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
+    if (error)
+      *error = code;
+    if (errorString)
+      *errorString = createCXString(err);
+  }
+  
+  void reportInvalidFile(llvm::StringRef err) {
+    return reportBad(CXLoadDiag_InvalidFile, err);
+  }
+
+  LoadResult readMetaBlock(llvm::BitstreamCursor &Stream);
+  
+  LoadResult readDiagnosticBlock(llvm::BitstreamCursor &Stream,
+                                 CXDiagnosticSetImpl &Diags,
+                                 CXLoadedDiagnosticSetImpl &TopDiags);
+
+  StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
+                                       llvm::StringRef errorContext,
+                                       unsigned &BlockOrRecordID,
+                                       const bool atTopLevel = false);
+  
+  
+  LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
+                        Strings &strings, llvm::StringRef errorContext,
+                        RecordData &Record,
+                        const char *BlobStart,
+                        unsigned BlobLen);
+
+  LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
+                        llvm::StringRef &RetStr,
+                        llvm::StringRef errorContext,
+                        RecordData &Record,
+                        const char *BlobStart,
+                        unsigned BlobLen);
+
+  LoadResult readRange(CXLoadedDiagnosticSetImpl &TopDiags,
+                       RecordData &Record, unsigned RecStartIdx,
+                       CXSourceRange &SR);
+  
+  LoadResult readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
+                          RecordData &Record, unsigned &offset,
+                          CXLoadedDiagnostic::Location &Loc);
+                       
+public:
+  DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
+    : error(e), errorString(es) {
+      if (error)
+        *error = CXLoadDiag_None;
+      if (errorString)
+        *errorString = createCXString("");
+    }
+  
+  CXDiagnosticSet load(const char *file);
+};
+}
+
+CXDiagnosticSet DiagLoader::load(const char *file) {
+  // Open the diagnostics file.
+  std::string ErrStr;
+  FileSystemOptions FO;
+  FileManager FileMgr(FO);
+
+  llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+  Buffer.reset(FileMgr.getBufferForFile(file));
+
+  if (!Buffer) {
+    reportBad(CXLoadDiag_CannotLoad, ErrStr);
+    return 0;
+  }
+
+  llvm::BitstreamReader StreamFile;
+  StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+                  (const unsigned char *)Buffer->getBufferEnd());
+
+  llvm::BitstreamCursor Stream;
+  Stream.init(StreamFile);
+
+  // Sniff for the signature.
+  if (Stream.Read(8) != 'D' ||
+      Stream.Read(8) != 'I' ||
+      Stream.Read(8) != 'A' ||
+      Stream.Read(8) != 'G') {
+    reportBad(CXLoadDiag_InvalidFile,
+              "Bad header in diagnostics file");
+    return 0;
+  }
+
+  llvm::OwningPtr<CXLoadedDiagnosticSetImpl>
+    Diags(new CXLoadedDiagnosticSetImpl());
+
+  while (true) {
+    unsigned BlockID = 0;
+    StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level", 
+                                               BlockID, true);
+    switch (Res) {
+      case Read_EndOfStream:
+        return (CXDiagnosticSet) Diags.take();
+      case Read_Failure:
+        return 0;
+      case Read_Record:
+        llvm_unreachable("Top-level does not have records");
+        return 0;
+      case Read_BlockEnd:
+        continue;
+      case Read_BlockBegin:
+        break;
+    }
+    
+    switch (BlockID) {
+      case serialized_diags::BLOCK_META:
+        if (readMetaBlock(Stream))
+          return 0;
+        break;
+      case serialized_diags::BLOCK_DIAG:
+        if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get()))
+          return 0;
+        break;
+      default:
+        if (!Stream.SkipBlock()) {
+          reportInvalidFile("Malformed block at top-level of diagnostics file");
+          return 0;
+        }
+        break;
+    }
+  }
+}
+
+StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
+                                                 llvm::StringRef errorContext,
+                                                 unsigned &blockOrRecordID,
+                                                 const bool atTopLevel) {
+  
+  blockOrRecordID = 0;
+
+  while (!Stream.AtEndOfStream()) {
+    unsigned Code = Stream.ReadCode();
+
+    // Handle the top-level specially.
+    if (atTopLevel) {
+      if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+        unsigned BlockID = Stream.ReadSubBlockID();
+        if (BlockID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
+          if (Stream.ReadBlockInfoBlock()) {
+            reportInvalidFile("Malformed BlockInfoBlock in diagnostics file");
+            return Read_Failure;
+          }
+          continue;
+        }
+        blockOrRecordID = BlockID;
+        return Read_BlockBegin;
+      }
+      reportInvalidFile("Only blocks can appear at the top of a "
+                        "diagnostic file");
+      return Read_Failure;
+    }
+    
+    switch ((llvm::bitc::FixedAbbrevIDs)Code) {
+      case llvm::bitc::ENTER_SUBBLOCK:
+        blockOrRecordID = Stream.ReadSubBlockID();
+        return Read_BlockBegin;
+      
+      case llvm::bitc::END_BLOCK:
+        if (Stream.ReadBlockEnd()) {
+          reportInvalidFile("Cannot read end of block");
+          return Read_Failure;
+        }
+        return Read_BlockEnd;
+        
+      case llvm::bitc::DEFINE_ABBREV:
+        Stream.ReadAbbrevRecord();
+        continue;
+        
+      case llvm::bitc::UNABBREV_RECORD:
+        reportInvalidFile("Diagnostics file should have no unabbreviated "
+                          "records");
+        return Read_Failure;
+      
+      default:
+        // We found a record.
+        blockOrRecordID = Code;
+        return Read_Record;
+    }
+  }
+  
+  if (atTopLevel)
+    return Read_EndOfStream;
+  
+  reportInvalidFile(Twine("Premature end of diagnostics file within ").str() + 
+                    errorContext.str());
+  return Read_Failure;
+}
+
+LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
+  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
+    reportInvalidFile("Malformed metadata block");
+    return Failure;
+  }
+
+  bool versionChecked = false;
+  
+  while (true) {
+    unsigned blockOrCode = 0;
+    StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block",
+                                               blockOrCode);
+    
+    switch(Res) {
+      case Read_EndOfStream:
+        llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock");
+      case Read_Failure:
+        return Failure;
+      case Read_Record:
+        break;
+      case Read_BlockBegin:
+        if (Stream.SkipBlock()) {
+          reportInvalidFile("Malformed metadata block");
+          return Failure;
+        }
+      case Read_BlockEnd:
+        if (!versionChecked) {
+          reportInvalidFile("Diagnostics file does not contain version"
+                            " information");
+          return Failure;
+        }
+        return Success;
+    }
+    
+    RecordData Record;
+    const char *Blob;
+    unsigned BlobLen;
+    unsigned recordID = Stream.ReadRecord(blockOrCode, Record, &Blob, &BlobLen);
+    
+    if (recordID == serialized_diags::RECORD_VERSION) {
+      if (Record.size() < 1) {
+        reportInvalidFile("malformed VERSION identifier in diagnostics file");
+        return Failure;
+      }
+      if (Record[0] > MaxSupportedVersion) {
+        reportInvalidFile("diagnosics file is a newer version than the one "
+                          "supported");
+        return Failure;
+      }
+      versionChecked = true;
+    }
+  }
+}
+
+LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
+                                  llvm::StringRef &RetStr,
+                                  llvm::StringRef errorContext,
+                                  RecordData &Record,
+                                  const char *BlobStart,
+                                  unsigned BlobLen) {
+  
+  // Basic buffer overflow check.
+  if (BlobLen > 65536) {
+    reportInvalidFile(std::string("Out-of-bounds string in ") +
+                      std::string(errorContext));
+    return Failure;
+  }
+  
+  if (Record.size() < 1 || BlobLen == 0) {
+    reportInvalidFile(std::string("Corrupted ") + std::string(errorContext)
+                      + std::string(" entry"));
+    return Failure;
+  }
+  
+  RetStr = TopDiags.makeString(BlobStart, BlobLen);
+  return Success;
+}
+
+LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
+                                  Strings &strings,
+                                  llvm::StringRef errorContext,
+                                  RecordData &Record,
+                                  const char *BlobStart,
+                                  unsigned BlobLen) {
+  llvm::StringRef RetStr;
+  if (readString(TopDiags, RetStr, errorContext, Record, BlobStart, BlobLen))
+    return Failure;
+  strings[Record[0]] = RetStr;
+  return Success;
+}
+
+LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
+                                    RecordData &Record, unsigned &offset,
+                                    CXLoadedDiagnostic::Location &Loc) {
+  if (Record.size() < offset + 3) {
+    reportInvalidFile("Corrupted source location");
+    return Failure;
+  }
+  
+  unsigned fileID = Record[offset++];
+  if (fileID == 0) {
+    // Sentinel value.
+    Loc.file = 0;
+    Loc.line = 0;
+    Loc.column = 0;
+    Loc.offset = 0;
+    return Success;
+  }
+
+  const FileEntry *FE = TopDiags.Files[fileID];
+  if (!FE) {
+    reportInvalidFile("Corrupted file entry in source location");
+    return Failure;
+  }
+  Loc.file = (void*) FE;
+  Loc.line = Record[offset++];
+  Loc.column = Record[offset++];
+  Loc.offset = Record[offset++];
+  return Success;
+}
+
+LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags,
+                                 RecordData &Record,
+                                 unsigned int RecStartIdx,
+                                 CXSourceRange &SR) {
+  CXLoadedDiagnostic::Location *Start, *End;
+  Start = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
+  End = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
+  
+  if (readLocation(TopDiags, Record, RecStartIdx, *Start))
+    return Failure;
+  if (readLocation(TopDiags, Record, RecStartIdx, *End))
+    return Failure;
+  
+  CXSourceLocation startLoc = makeLocation(Start);
+  CXSourceLocation endLoc = makeLocation(End);
+  SR = clang_getRange(startLoc, endLoc);
+  return Success;  
+}
+
+LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
+                                           CXDiagnosticSetImpl &Diags,
+                                           CXLoadedDiagnosticSetImpl &TopDiags){
+
+  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
+    reportInvalidFile("malformed diagnostic block");
+    return Failure;
+  }
+  
+  llvm::OwningPtr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic());
+  RecordData Record;
+  
+  while (true) {
+    unsigned blockOrCode = 0;
+    StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block",
+                                               blockOrCode);
+    switch (Res) {
+      case Read_EndOfStream:
+        llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock");
+        return Failure;
+      case Read_Failure:
+        return Failure;
+      case Read_BlockBegin: {
+        // The only blocks we care about are subdiagnostics.
+        if (blockOrCode != serialized_diags::BLOCK_DIAG) {
+          if (!Stream.SkipBlock()) {
+            reportInvalidFile("Invalid subblock in Diagnostics block");
+            return Failure;
+          }
+        } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(),
+                                       TopDiags)) {
+          return Failure;
+        }
+
+        continue;
+      }
+      case Read_BlockEnd:
+        Diags.appendDiagnostic(D.take());        
+        return Success;
+      case Read_Record:
+        break;
+    }
+    
+    // Read the record.
+    Record.clear();
+    const char *BlobStart = 0;
+    unsigned BlobLen = 0;
+    unsigned recID = Stream.ReadRecord(blockOrCode, Record,
+                                       BlobStart, BlobLen);
+    
+    if (recID < serialized_diags::RECORD_FIRST ||
+        recID > serialized_diags::RECORD_LAST)
+      continue;
+    
+    switch ((serialized_diags::RecordIDs)recID) {  
+      case serialized_diags::RECORD_VERSION:
+        continue;
+      case serialized_diags::RECORD_CATEGORY:
+        if (readString(TopDiags, TopDiags.Categories, "category", Record,
+                       BlobStart, BlobLen))
+          return Failure;
+        continue;
+      
+      case serialized_diags::RECORD_DIAG_FLAG:
+        if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record,
+                       BlobStart, BlobLen))
+          return Failure;
+        continue;
+        
+      case serialized_diags::RECORD_FILENAME: {
+        if (readString(TopDiags, TopDiags.FileNames, "filename", Record,
+                       BlobStart, BlobLen))
+          return Failure;
+
+        if (Record.size() < 3) {
+          reportInvalidFile("Invalid file entry");
+          return Failure;
+        }
+        
+        const FileEntry *FE =
+          TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]],
+                                            /* size */ Record[1],
+                                            /* time */ Record[2]);
+        
+        TopDiags.Files[Record[0]] = FE;
+        continue;
+      }
+
+      case serialized_diags::RECORD_SOURCE_RANGE: {
+        CXSourceRange SR;
+        if (readRange(TopDiags, Record, 0, SR))
+          return Failure;
+        D->Ranges.push_back(SR);
+        continue;
+      }
+      
+      case serialized_diags::RECORD_FIXIT: {
+        CXSourceRange SR;
+        if (readRange(TopDiags, Record, 0, SR))
+          return Failure;
+        llvm::StringRef RetStr;
+        if (readString(TopDiags, RetStr, "FIXIT", Record, BlobStart, BlobLen))
+          return Failure;
+        D->FixIts.push_back(std::make_pair(SR, createCXString(RetStr, false)));
+        continue;        
+      }
+        
+      case serialized_diags::RECORD_DIAG: {
+        D->severity = Record[0];
+        unsigned offset = 1;
+        if (readLocation(TopDiags, Record, offset, D->DiagLoc))
+          return Failure;
+        D->category = Record[offset++];
+        unsigned diagFlag = Record[offset++];
+        D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : "";
+        D->Spelling = TopDiags.makeString(BlobStart, BlobLen);
+        continue;
+      }
+    }
+  }
+}
+
+extern "C" {
+CXDiagnosticSet clang_loadDiagnostics(const char *file,
+                                      enum CXLoadDiag_Error *error,
+                                      CXString *errorString) {
+  DiagLoader L(error, errorString);
+  return L.load(file);
+}
+} // end extern 'C'.

Added: cfe/trunk/tools/libclang/CXLoadedDiagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXLoadedDiagnostic.h?rev=144269&view=auto
==============================================================================
--- cfe/trunk/tools/libclang/CXLoadedDiagnostic.h (added)
+++ cfe/trunk/tools/libclang/CXLoadedDiagnostic.h Thu Nov 10 02:43:12 2011
@@ -0,0 +1,90 @@
+/*===-- CXLoadedDiagnostic.h - Handling of persisent diags ------*- C++ -*-===*\
+|*                                                                            *|
+|*                     The LLVM Compiler Infrastructure                       *|
+|*                                                                            *|
+|* This file is distributed under the University of Illinois Open Source      *|
+|* License. See LICENSE.TXT for details.                                      *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*|
+|*                                                                            *|
+|* Implements handling of persisent diagnostics.                              *|
+|*                                                                            *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_CLANG_CINDEX_LOADED_DIAGNOSTIC_H
+#define LLVM_CLANG_CINDEX_LOADED_DIAGNOSTIC_H
+
+#include "CIndexDiagnostic.h"
+#include "llvm/ADT/StringRef.h"
+#include "clang/Basic/LLVM.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+class CXLoadedDiagnostic : public CXDiagnosticImpl {
+public:
+  CXLoadedDiagnostic() : CXDiagnosticImpl(LoadedDiagnosticKind),
+    severity(0), category(0) {}
+
+  virtual ~CXLoadedDiagnostic();
+  
+  /// \brief Return the severity of the diagnostic.
+  virtual CXDiagnosticSeverity getSeverity() const;
+  
+  /// \brief Return the location of the diagnostic.
+  virtual CXSourceLocation getLocation() const;
+  
+  /// \brief Return the spelling of the diagnostic.
+  virtual CXString getSpelling() const;
+  
+  /// \brief Return the text for the diagnostic option.
+  virtual CXString getDiagnosticOption(CXString *Disable) const;
+  
+  /// \brief Return the category of the diagnostic.
+  virtual unsigned getCategory() const;
+  
+  /// \brief Return the number of source ranges for the diagnostic.
+  virtual unsigned getNumRanges() const;
+  
+  /// \brief Return the source ranges for the diagnostic.
+  virtual CXSourceRange getRange(unsigned Range) const;
+  
+  /// \brief Return the number of FixIts.
+  virtual unsigned getNumFixIts() const;
+  
+  /// \brief Return the FixIt information (source range and inserted text).
+  virtual CXString getFixIt(unsigned FixIt,
+                            CXSourceRange *ReplacementRange) const;
+  
+  static bool classof(const CXDiagnosticImpl *D) {
+    return D->getKind() == LoadedDiagnosticKind;
+  }
+  
+  /// \brief Decode the CXSourceLocation into file, line, column, and offset.
+  static void decodeLocation(CXSourceLocation location,
+                             CXFile *file,
+                             unsigned *line,
+                             unsigned *column,
+                             unsigned *offset);
+
+  struct Location {
+    CXFile file;
+    unsigned line;
+    unsigned column;
+    unsigned offset;
+    
+    Location() : line(0), column(0), offset(0) {}    
+  };
+  
+  Location DiagLoc;
+
+  std::vector<CXSourceRange> Ranges;
+  std::vector<std::pair<CXSourceRange, CXString> > FixIts;
+  llvm::StringRef Spelling;
+  llvm::StringRef DiagOption;
+  unsigned severity;
+  unsigned category;
+};
+}
+
+#endif

Modified: cfe/trunk/tools/libclang/CXSourceLocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXSourceLocation.cpp?rev=144269&r1=144268&r2=144269&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXSourceLocation.cpp (original)
+++ cfe/trunk/tools/libclang/CXSourceLocation.cpp Thu Nov 10 02:43:12 2011
@@ -17,6 +17,7 @@
 #include "CXString.h"
 #include "CXSourceLocation.h"
 #include "CXTranslationUnit.h"
+#include "CXLoadedDiagnostic.h"
 
 using namespace clang;
 using namespace clang::cxstring;
@@ -54,6 +55,13 @@
 }
 
 CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
+  if (!isASTUnitSourceLocation(begin)) {
+    if (isASTUnitSourceLocation(end))
+      return clang_getNullRange();
+    CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
+    return Result;
+  }
+  
   if (begin.ptr_data[0] != end.ptr_data[0] ||
       begin.ptr_data[1] != end.ptr_data[1])
     return clang_getNullRange();
@@ -64,7 +72,6 @@
   return Result;
 }
 
-  
 unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
   return range1.ptr_data[0] == range2.ptr_data[0]
     && range1.ptr_data[1] == range2.ptr_data[1]
@@ -78,12 +85,24 @@
   
   
 CXSourceLocation clang_getRangeStart(CXSourceRange range) {
+  // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
+  if ((uintptr_t)range.ptr_data[0] & 0x1) {
+    CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 };
+    return Result;    
+  }
+  
   CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
     range.begin_int_data };
   return Result;
 }
 
 CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
+  // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
+  if ((uintptr_t)range.ptr_data[0] & 0x1) {
+    CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 };
+    return Result;    
+  }
+
   CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
     range.end_int_data };
   return Result;
@@ -182,41 +201,40 @@
                                 unsigned *column,
                                 unsigned *offset) {
   
-  if (isASTUnitSourceLocation(location)) {  
-    SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
-  
-    if (!location.ptr_data[0] || Loc.isInvalid()) {
-      createNullLocation(file, line, column, offset);
-      return;
-    }
-  
-    const SourceManager &SM =
-    *static_cast<const SourceManager*>(location.ptr_data[0]);
-    SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
-    
-    // Check that the FileID is invalid on the expansion location.
-    // This can manifest in invalid code.
-    FileID fileID = SM.getFileID(ExpansionLoc);
-    bool Invalid = false;
-    const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
-    if (Invalid || !sloc.isFile()) {
-      createNullLocation(file, line, column, offset);
-      return;
-    }
-    
-    if (file)
-      *file = (void *)SM.getFileEntryForSLocEntry(sloc);
-    if (line)
-      *line = SM.getExpansionLineNumber(ExpansionLoc);
-    if (column)
-      *column = SM.getExpansionColumnNumber(ExpansionLoc);
-    if (offset)
-      *offset = SM.getDecomposedLoc(ExpansionLoc).second;
+  if (!isASTUnitSourceLocation(location)) {
+    CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
+    return;
+  }
+
+  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+
+  if (!location.ptr_data[0] || Loc.isInvalid()) {
+    createNullLocation(file, line, column, offset);
+    return;
+  }
+
+  const SourceManager &SM =
+  *static_cast<const SourceManager*>(location.ptr_data[0]);
+  SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
+  
+  // Check that the FileID is invalid on the expansion location.
+  // This can manifest in invalid code.
+  FileID fileID = SM.getFileID(ExpansionLoc);
+  bool Invalid = false;
+  const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
+  if (Invalid || !sloc.isFile()) {
+    createNullLocation(file, line, column, offset);
     return;
   }
   
-  // FIXME:
-  createNullLocation(file, line, column, offset);
+  if (file)
+    *file = (void *)SM.getFileEntryForSLocEntry(sloc);
+  if (line)
+    *line = SM.getExpansionLineNumber(ExpansionLoc);
+  if (column)
+    *column = SM.getExpansionColumnNumber(ExpansionLoc);
+  if (offset)
+    *offset = SM.getDecomposedLoc(ExpansionLoc).second;
 }
 
 void clang_getPresumedLocation(CXSourceLocation location,
@@ -224,28 +242,29 @@
                                unsigned *line,
                                unsigned *column) {
   
-  if (isASTUnitSourceLocation(location)) {
-    SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
-  
-    if (!location.ptr_data[0] || Loc.isInvalid())
-      createNullLocation(filename, line, column);
-    else {
-      const SourceManager &SM =
-      *static_cast<const SourceManager*>(location.ptr_data[0]);
-      PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
-      
-      if (filename)
-        *filename = createCXString(PreLoc.getFilename());
-      if (line)
-        *line = PreLoc.getLine();
-      if (column)
-        *column = PreLoc.getColumn();
-    }
+  if (!isASTUnitSourceLocation(location)) {
+    // Other SourceLocation implementations do not support presumed locations
+    // at this time.
+    createNullLocation(filename, line, column);
     return;
   }
-  
-  // FIXME:
-  createNullLocation(filename, line, column);
+
+  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+
+  if (!location.ptr_data[0] || Loc.isInvalid())
+    createNullLocation(filename, line, column);
+  else {
+    const SourceManager &SM =
+    *static_cast<const SourceManager*>(location.ptr_data[0]);
+    PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
+    
+    if (filename)
+      *filename = createCXString(PreLoc.getFilename());
+    if (line)
+      *line = PreLoc.getLine();
+    if (column)
+      *column = PreLoc.getColumn();
+  }
 }
 
 void clang_getInstantiationLocation(CXSourceLocation location,
@@ -263,44 +282,44 @@
                                unsigned *column,
                                unsigned *offset) {
   
-  if (isASTUnitSourceLocation(location)) {
-    SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
-    
-    if (!location.ptr_data[0] || Loc.isInvalid())
-      return createNullLocation(file, line, column, offset);
-    
-    const SourceManager &SM =
-    *static_cast<const SourceManager*>(location.ptr_data[0]);
-    SourceLocation SpellLoc = Loc;
-    if (SpellLoc.isMacroID()) {
-      SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc);
-      if (SimpleSpellingLoc.isFileID() &&
-          SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
-        SpellLoc = SimpleSpellingLoc;
-      else
-        SpellLoc = SM.getExpansionLoc(SpellLoc);
-    }
-    
-    std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
-    FileID FID = LocInfo.first;
-    unsigned FileOffset = LocInfo.second;
-    
-    if (FID.isInvalid())
-      return createNullLocation(file, line, column, offset);
-    
-    if (file)
-      *file = (void *)SM.getFileEntryForID(FID);
-    if (line)
-      *line = SM.getLineNumber(FID, FileOffset);
-    if (column)
-      *column = SM.getColumnNumber(FID, FileOffset);
-    if (offset)
-      *offset = FileOffset;
+  if (!isASTUnitSourceLocation(location)) {
+    CXLoadedDiagnostic::decodeLocation(location, file, line,
+                                           column, offset);
     return;
   }
-
-  // FIXME:
-  createNullLocation(file, line, column, offset);
+  
+  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+  
+  if (!location.ptr_data[0] || Loc.isInvalid())
+    return createNullLocation(file, line, column, offset);
+  
+  const SourceManager &SM =
+  *static_cast<const SourceManager*>(location.ptr_data[0]);
+  SourceLocation SpellLoc = Loc;
+  if (SpellLoc.isMacroID()) {
+    SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc);
+    if (SimpleSpellingLoc.isFileID() &&
+        SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
+      SpellLoc = SimpleSpellingLoc;
+    else
+      SpellLoc = SM.getExpansionLoc(SpellLoc);
+  }
+  
+  std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
+  FileID FID = LocInfo.first;
+  unsigned FileOffset = LocInfo.second;
+  
+  if (FID.isInvalid())
+    return createNullLocation(file, line, column, offset);
+  
+  if (file)
+    *file = (void *)SM.getFileEntryForID(FID);
+  if (line)
+    *line = SM.getLineNumber(FID, FileOffset);
+  if (column)
+    *column = SM.getColumnNumber(FID, FileOffset);
+  if (offset)
+    *offset = FileOffset;
 }
 
 } // end extern "C"

Modified: cfe/trunk/tools/libclang/CXStoredDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXStoredDiagnostic.cpp?rev=144269&r1=144268&r2=144269&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXStoredDiagnostic.cpp (original)
+++ cfe/trunk/tools/libclang/CXStoredDiagnostic.cpp Thu Nov 10 02:43:12 2011
@@ -28,9 +28,6 @@
 using namespace clang::cxloc;
 using namespace clang::cxstring;
 
-// Needed for vtable of CXPersisetntDiagnostic.
-CXDiagnosticImpl::~CXDiagnosticImpl() {}
-
 CXDiagnosticSeverity CXStoredDiagnostic::getSeverity() const {
   switch (Diag.getLevel()) {
     case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored;

Modified: cfe/trunk/tools/libclang/CXTranslationUnit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXTranslationUnit.h?rev=144269&r1=144268&r2=144269&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXTranslationUnit.h (original)
+++ cfe/trunk/tools/libclang/CXTranslationUnit.h Thu Nov 10 02:43:12 2011
@@ -18,6 +18,7 @@
 struct CXTranslationUnitImpl {
   void *TUData;
   void *StringPool;
+  void *Diagnostics;
 };
 }
 
@@ -27,7 +28,7 @@
 namespace cxtu {
 
 CXTranslationUnitImpl *MakeCXTranslationUnit(ASTUnit *TU);
-
+  
 class CXTUOwner {
   CXTranslationUnitImpl *TU;
   

Modified: cfe/trunk/tools/libclang/libclang.exports
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/libclang.exports?rev=144269&r1=144268&r2=144269&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/libclang.exports (original)
+++ cfe/trunk/tools/libclang/libclang.exports Thu Nov 10 02:43:12 2011
@@ -32,6 +32,7 @@
 clang_disposeCXTUResourceUsage
 clang_disposeCodeCompleteResults
 clang_disposeDiagnostic
+clang_disposeDiagnosticSet
 clang_disposeIndex
 clang_disposeOverriddenCursors
 clang_disposeString
@@ -53,6 +54,7 @@
 clang_getCXXAccessSpecifier
 clang_getCanonicalCursor
 clang_getCanonicalType
+clang_getChildDiagnostics
 clang_getClangVersion
 clang_getCompletionAnnotation
 clang_getCompletionAvailability
@@ -86,6 +88,7 @@
 clang_getDiagnosticCategory
 clang_getDiagnosticCategoryName
 clang_getDiagnosticFixIt
+clang_getDiagnosticInSet
 clang_getDiagnosticLocation
 clang_getDiagnosticNumFixIts
 clang_getDiagnosticNumRanges
@@ -108,6 +111,7 @@
 clang_getNullRange
 clang_getNumCompletionChunks
 clang_getNumDiagnostics
+clang_getNumDiagnosticsInSet
 clang_getNumOverloadedDecls
 clang_getOverloadedDecl
 clang_getOverriddenCursors
@@ -150,6 +154,7 @@
 clang_isUnexposed
 clang_isVirtualBase
 clang_isVolatileQualifiedType
+clang_loadDiagnostics
 clang_parseTranslationUnit
 clang_remap_dispose
 clang_remap_getFilenames





More information about the cfe-commits mailing list