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

Argyrios Kyrtzidis kyrtzidis at apple.com
Thu Nov 10 10:32:38 PST 2011


On Nov 10, 2011, at 12:43 AM, Ted Kremenek wrote:

> 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
> +};

CXLoadDiag_Error seems useful for other functions that load a file as well, like the one that reads an AST file, the one that reads file remappings, etc.
Maybe change it to CXLoadFile_Error so it can be reused ?

> +  
> +/**
> + * \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);
> }

Instead of passing the TokSize to AddLocToRecord you could adjust the source location, like:

  AddLocToRecord(Range.getBegin(), Record);
  SourceLocation CharEnd = Range.getEnd();
  if (Range.isTokenRange()) {
    unsigned TokSize = Lexer::MeasureTokenLength(CharEnd,
                                        Diags.getSourceManager(),
                                        *LangOpts);
    CharEnd = CharEnd.getLocWithOffset(TokSize);
  }
  
  AddLocToRecord(CharEnd, Record);


> 
> 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;
> +}

Is this modification to CXSourceLocation so that the diagnostic location becomes independent of a SourceManager ?

Why not introduce a new kind of location (like CXFileLocation or something) instead ? If you remove the SourceManager you "disable" the functionality of CXSourceLocation anyway, e.g. while previously you could go through the expansion stack, get presumed location, etc., you can't do that with this new kind of location. Seems better to be clear in the API.

-Argyrios

> +
> +//===----------------------------------------------------------------------===//
> +// 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
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20111110/c48eeacc/attachment.html>


More information about the cfe-commits mailing list