[cfe-commits] r144269 - in /cfe/trunk: include/clang-c/ include/clang/Frontend/ lib/Frontend/ tools/c-index-test/ tools/libclang/
Nico Weber
thakis at chromium.org
Fri Apr 25 12:41:27 PDT 2014
Zombie review! (below)
On Thu, Nov 10, 2011 at 12:43 AM, Ted Kremenek <kremenek at apple.com> 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
> +};
> +
> +/**
> + * \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.
clang_codeCompleteGetDiagnostic() also needed this function to delete
the argument (see the call to clang_codeCompleteGetDiagnostic()
c-index-test.c and the dispose call two lines below – that's now a
leak).
Do you have an opinion on how to fix this? Should the result of
clang_codeCompleteAt() own diagnostics associated with the completion?
> }
>
> 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
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list