diff options
-rw-r--r-- | include/clang-c/Index.h | 58 | ||||
-rw-r--r-- | include/clang/Basic/Diagnostic.h | 51 | ||||
-rw-r--r-- | include/clang/Frontend/ASTUnit.h | 23 | ||||
-rw-r--r-- | lib/Basic/Diagnostic.cpp | 310 | ||||
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 69 | ||||
-rw-r--r-- | lib/Frontend/CompilerInstance.cpp | 2 | ||||
-rw-r--r-- | test/Index/cindex-on-invalid.m | 1 | ||||
-rw-r--r-- | tools/CIndex/CIndex.cpp | 35 | ||||
-rw-r--r-- | tools/CIndex/CIndex.exports | 5 | ||||
-rw-r--r-- | tools/CIndex/CIndexCodeCompletion.cpp | 56 | ||||
-rw-r--r-- | tools/CIndex/CIndexDiagnostic.cpp | 158 | ||||
-rw-r--r-- | tools/CIndex/CIndexDiagnostic.h | 48 | ||||
-rw-r--r-- | tools/c-index-test/c-index-test.c | 44 |
13 files changed, 504 insertions, 356 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 0c671048dc..99c129b220 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -416,17 +416,27 @@ enum CXFixItKind { typedef void *CXDiagnostic; /** - * \brief Callback function invoked for each diagnostic emitted during - * translation. + * \brief Determine the number of diagnostics produced for the given + * translation unit. + */ +CINDEX_LINKAGE unsigned clang_getNumDiagnostics(CXTranslationUnit Unit); + +/** + * \brief Retrieve a diagnostic associated with the given translation unit. * - * \param Diagnostic the diagnostic emitted during translation. This - * diagnostic pointer is only valid during the execution of the - * callback. + * \param Unit the translation unit to query. + * \param Index the zero-based diagnostic number to retrieve. * - * \param ClientData the callback client data. + * \returns the requested diagnostic. This diagnostic must be freed + * via a call to \c clang_disposeDiagnostic(). */ -typedef void (*CXDiagnosticCallback)(CXDiagnostic Diagnostic, - CXClientData ClientData); +CINDEX_LINKAGE CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, + unsigned Index); + +/** + * \brief Destroy a diagnostic. + */ +CINDEX_LINKAGE void clang_disposeDiagnostic(CXDiagnostic Diagnostic); /** * \brief Determine the severity of the given diagnostic. @@ -600,17 +610,13 @@ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( int num_clang_command_line_args, const char **clang_command_line_args, unsigned num_unsaved_files, - struct CXUnsavedFile *unsaved_files, - CXDiagnosticCallback diag_callback, - CXClientData diag_client_data); + struct CXUnsavedFile *unsaved_files); /** * \brief Create a translation unit from an AST file (-emit-ast). */ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit(CXIndex, - const char *ast_filename, - CXDiagnosticCallback diag_callback, - CXClientData diag_client_data); + const char *ast_filename); /** * \brief Destroy the specified CXTranslationUnit object. @@ -1625,9 +1631,7 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, struct CXUnsavedFile *unsaved_files, const char *complete_filename, unsigned complete_line, - unsigned complete_column, - CXDiagnosticCallback diag_callback, - CXClientData diag_client_data); + unsigned complete_column); /** * \brief Free the given set of code-completion results. @@ -1636,6 +1640,26 @@ CINDEX_LINKAGE void clang_disposeCodeCompleteResults(CXCodeCompleteResults *Results); /** + * \brief Determine the number of diagnostics produced prior to the + * location where code completion was performed. + */ +CINDEX_LINKAGE +unsigned clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *Results); + +/** + * \brief Retrieve a diagnostic associated with the given code completion. + * + * \param Result the code completion results 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_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results, + unsigned Index); + +/** * @} */ diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index d2516f8695..d6c8797fc9 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -403,13 +403,6 @@ public: /// \brief Clear out the current diagnostic. void Clear() { CurDiagID = ~0U; } - /// Deserialize - Deserialize the first diagnostic within the memory - /// [Memory, MemoryEnd), producing a new diagnostic builder describing the - /// deserialized diagnostic. If the memory does not contain a - /// diagnostic, returns a diagnostic builder with no diagnostic ID. - DiagnosticBuilder Deserialize(FileManager &FM, SourceManager &SM, - const char *&Memory, const char *MemoryEnd); - private: /// getDiagnosticMappingInfo - Return the mapping info currently set for the /// specified builtin diagnostic. This returns the high bit encoding, or zero @@ -799,12 +792,54 @@ public: /// output buffer using the arguments stored in this diagnostic. void FormatDiagnostic(const char *DiagStr, const char *DiagEnd, llvm::SmallVectorImpl<char> &OutStr) const; +}; + +/** + * \brief Represents a diagnostic in a form that can be serialized and + * deserialized. + */ +class StoredDiagnostic { + Diagnostic::Level Level; + FullSourceLoc Loc; + std::string Message; + std::vector<SourceRange> Ranges; + std::vector<CodeModificationHint> FixIts; + +public: + StoredDiagnostic(); + StoredDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info); + StoredDiagnostic(Diagnostic::Level Level, llvm::StringRef Message); + ~StoredDiagnostic(); + + /// \brief Evaluates true when this object stores a diagnostic. + operator bool() const { return Message.size() > 0; } + + Diagnostic::Level getLevel() const { return Level; } + const FullSourceLoc &getLocation() const { return Loc; } + llvm::StringRef getMessage() const { return Message; } + + typedef std::vector<SourceRange>::const_iterator range_iterator; + range_iterator range_begin() const { return Ranges.begin(); } + range_iterator range_end() const { return Ranges.end(); } + unsigned range_size() const { return Ranges.size(); } + + typedef std::vector<CodeModificationHint>::const_iterator fixit_iterator; + fixit_iterator fixit_begin() const { return FixIts.begin(); } + fixit_iterator fixit_end() const { return FixIts.end(); } + unsigned fixit_size() const { return FixIts.size(); } /// Serialize - Serialize the given diagnostic (with its diagnostic /// level) to the given stream. Serialization is a lossy operation, /// since the specific diagnostic ID and any macro-instantiation /// information is lost. - void Serialize(Diagnostic::Level DiagLevel, llvm::raw_ostream &OS) const; + void Serialize(llvm::raw_ostream &OS) const; + + /// Deserialize - Deserialize the first diagnostic within the memory + /// [Memory, MemoryEnd), producing a new diagnostic builder describing the + /// deserialized diagnostic. If the memory does not contain a + /// diagnostic, returns a diagnostic builder with no diagnostic ID. + static StoredDiagnostic Deserialize(FileManager &FM, SourceManager &SM, + const char *&Memory, const char *MemoryEnd); }; /// DiagnosticClient - This is an abstract interface implemented by clients of diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index f122dd954d..71a895ffb9 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -18,6 +18,7 @@ #include "llvm/ADT/OwningPtr.h" #include "clang/Basic/FileManager.h" #include "clang/Index/ASTLocation.h" +#include "llvm/ADT/SmallVector.h" #include <string> #include <vector> #include <cassert> @@ -80,6 +81,10 @@ class ASTUnit { // Critical optimization when using clang_getCursor(). ASTLocation LastLoc; + /// \brief The set of diagnostics produced when creating this + /// translation unit. + llvm::SmallVector<StoredDiagnostic, 4> Diagnostics; + ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT @@ -120,6 +125,15 @@ public: return TopLevelDecls; } + // Retrieve the diagnostics associated with this AST + typedef const StoredDiagnostic * diag_iterator; + diag_iterator diag_begin() const { return Diagnostics.begin(); } + diag_iterator diag_end() const { return Diagnostics.end(); } + unsigned diag_size() const { return Diagnostics.size(); } + llvm::SmallVector<StoredDiagnostic, 4> &getDiagnostics() { + return Diagnostics; + } + /// \brief A mapping from a file name to the memory buffer that stores the /// remapped contents of that file. typedef std::pair<std::string, const llvm::MemoryBuffer *> RemappedFile; @@ -136,7 +150,8 @@ public: Diagnostic &Diags, bool OnlyLocalDecls = false, RemappedFile *RemappedFiles = 0, - unsigned NumRemappedFiles = 0); + unsigned NumRemappedFiles = 0, + bool CaptureDiagnostics = false); /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a /// CompilerInvocation object. @@ -151,7 +166,8 @@ public: // shouldn't need to specify them at construction time. static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI, Diagnostic &Diags, - bool OnlyLocalDecls = false); + bool OnlyLocalDecls = false, + bool CaptureDiagnostics = false); /// LoadFromCommandLine - Create an ASTUnit from a vector of command line /// arguments, which must specify exactly one source file. @@ -173,7 +189,8 @@ public: llvm::StringRef ResourceFilesPath, bool OnlyLocalDecls = false, RemappedFile *RemappedFiles = 0, - unsigned NumRemappedFiles = 0); + unsigned NumRemappedFiles = 0, + bool CaptureDiagnostics = false); }; } // namespace clang diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 094f7760a8..e92d1e56ca 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -387,123 +387,6 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const { return Result; } -static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, - unsigned &Value) { - if (Memory + sizeof(unsigned) > MemoryEnd) - return true; - - memmove(&Value, Memory, sizeof(unsigned)); - Memory += sizeof(unsigned); - return false; -} - -static bool ReadSourceLocation(FileManager &FM, SourceManager &SM, - const char *&Memory, const char *MemoryEnd, - SourceLocation &Location) { - // Read the filename. - unsigned FileNameLen = 0; - if (ReadUnsigned(Memory, MemoryEnd, FileNameLen) || - Memory + FileNameLen > MemoryEnd) - return true; - - llvm::StringRef FileName(Memory, FileNameLen); - Memory += FileNameLen; - - // Read the line, column. - unsigned Line = 0, Column = 0; - if (ReadUnsigned(Memory, MemoryEnd, Line) || - ReadUnsigned(Memory, MemoryEnd, Column)) - return true; - - if (FileName.empty()) { - Location = SourceLocation(); - return false; - } - - const FileEntry *File = FM.getFile(FileName); - if (!File) - return true; - - // Make sure that this file has an entry in the source manager. - if (!SM.hasFileInfo(File)) - SM.createFileID(File, SourceLocation(), SrcMgr::C_User); - - Location = SM.getLocation(File, Line, Column); - return false; -} - -DiagnosticBuilder Diagnostic::Deserialize(FileManager &FM, SourceManager &SM, - const char *&Memory, - const char *MemoryEnd) { - if (Memory == MemoryEnd) - return DiagnosticBuilder(0); - - // Read the severity level. - unsigned Level = 0; - if (ReadUnsigned(Memory, MemoryEnd, Level) || Level > Fatal) - return DiagnosticBuilder(0); - - // Read the source location. - SourceLocation Location; - if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Location)) - return DiagnosticBuilder(0); - - // Read the diagnostic text. - if (Memory == MemoryEnd) - return DiagnosticBuilder(0); - - unsigned MessageLen = 0; - if (ReadUnsigned(Memory, MemoryEnd, MessageLen) || - Memory + MessageLen > MemoryEnd) - return DiagnosticBuilder(0); - - llvm::StringRef Message(Memory, MessageLen); - Memory += MessageLen; - - // At this point, we have enough information to form a diagnostic. Do so. - unsigned DiagID = getCustomDiagID((enum Level)Level, Message); - DiagnosticBuilder DB = Report(FullSourceLoc(Location, SM), DiagID); - if (Memory == MemoryEnd) - return DB; - - // Read the source ranges. - unsigned NumSourceRanges = 0; - if (ReadUnsigned(Memory, MemoryEnd, NumSourceRanges)) - return DB; - for (unsigned I = 0; I != NumSourceRanges; ++I) { - SourceLocation Begin, End; - if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Begin) || - ReadSourceLocation(FM, SM, Memory, MemoryEnd, End)) - return DB; - - DB << SourceRange(Begin, End); - } - - // Read the fix-it hints. - unsigned NumFixIts = 0; - if (ReadUnsigned(Memory, MemoryEnd, NumFixIts)) - return DB; - for (unsigned I = 0; I != NumFixIts; ++I) { - SourceLocation RemoveBegin, RemoveEnd, InsertionLoc; - unsigned InsertLen = 0; - if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveBegin) || - ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveEnd) || - ReadSourceLocation(FM, SM, Memory, MemoryEnd, InsertionLoc) || - ReadUnsigned(Memory, MemoryEnd, InsertLen) || - Memory + InsertLen > MemoryEnd) - return DB; - - CodeModificationHint Hint; - Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd); - Hint.InsertionLoc = InsertionLoc; - Hint.CodeToInsert.assign(Memory, Memory + InsertLen); - Memory += InsertLen; - DB << Hint; - } - - return DB; -} - struct WarningOption { const char *Name; const short *Members; @@ -1036,6 +919,31 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, } } +StoredDiagnostic::StoredDiagnostic() { } + +StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, + llvm::StringRef Message) + : Level(Level), Message(Message) { } + +StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, + const DiagnosticInfo &Info) + : Level(Level), Loc(Info.getLocation()) +{ + llvm::SmallString<64> Message; + Info.FormatDiagnostic(Message); + this->Message.assign(Message.begin(), Message.end()); + + Ranges.reserve(Info.getNumRanges()); + for (unsigned I = 0, N = Info.getNumRanges(); I != N; ++I) + Ranges.push_back(Info.getRange(I)); + + FixIts.reserve(Info.getNumCodeModificationHints()); + for (unsigned I = 0, N = Info.getNumCodeModificationHints(); I != N; ++I) + FixIts.push_back(Info.getCodeModificationHint(I)); +} + +StoredDiagnostic::~StoredDiagnostic() { } + static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) { OS.write((const char *)&Value, sizeof(unsigned)); } @@ -1065,27 +973,24 @@ static void WriteSourceLocation(llvm::raw_ostream &OS, WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second)); } -void DiagnosticInfo::Serialize(Diagnostic::Level DiagLevel, - llvm::raw_ostream &OS) const { +void StoredDiagnostic::Serialize(llvm::raw_ostream &OS) const { SourceManager *SM = 0; if (getLocation().isValid()) SM = &const_cast<SourceManager &>(getLocation().getManager()); // Write the diagnostic level and location. - WriteUnsigned(OS, (unsigned)DiagLevel); + WriteUnsigned(OS, (unsigned)Level); WriteSourceLocation(OS, SM, getLocation()); // Write the diagnostic message. llvm::SmallString<64> Message; - FormatDiagnostic(Message); - WriteString(OS, Message); + WriteString(OS, getMessage()); // Count the number of ranges that don't point into macros, since // only simple file ranges serialize well. unsigned NumNonMacroRanges = 0; - for (unsigned I = 0, N = getNumRanges(); I != N; ++I) { - SourceRange R = getRange(I); - if (R.getBegin().isMacroID() || R.getEnd().isMacroID()) + for (range_iterator R = range_begin(), REnd = range_end(); R != REnd; ++R) { + if (R->getBegin().isMacroID() || R->getEnd().isMacroID()) continue; ++NumNonMacroRanges; @@ -1094,44 +999,165 @@ void DiagnosticInfo::Serialize(Diagnostic::Level DiagLevel, // Write the ranges. WriteUnsigned(OS, NumNonMacroRanges); if (NumNonMacroRanges) { - for (unsigned I = 0, N = getNumRanges(); I != N; ++I) { - SourceRange R = getRange(I); - if (R.getBegin().isMacroID() || R.getEnd().isMacroID()) + for (range_iterator R = range_begin(), REnd = range_end(); R != REnd; ++R) { + if (R->getBegin().isMacroID() || R->getEnd().isMacroID()) continue; - WriteSourceLocation(OS, SM, R.getBegin()); - WriteSourceLocation(OS, SM, R.getEnd()); + WriteSourceLocation(OS, SM, R->getBegin()); + WriteSourceLocation(OS, SM, R->getEnd()); } } // Determine if all of the fix-its involve rewrites with simple file // locations (not in macro instantiations). If so, we can write // fix-it information. - unsigned NumFixIts = getNumCodeModificationHints(); - for (unsigned I = 0; I != NumFixIts; ++I) { - const CodeModificationHint &Hint = getCodeModificationHint(I); - if (Hint.RemoveRange.isValid() && - (Hint.RemoveRange.getBegin().isMacroID() || - Hint.RemoveRange.getEnd().isMacroID())) { + unsigned NumFixIts = 0; + for (fixit_iterator F = fixit_begin(), FEnd = fixit_end(); F != FEnd; ++F) { + if (F->RemoveRange.isValid() && + (F->RemoveRange.getBegin().isMacroID() || + F->RemoveRange.getEnd().isMacroID())) { NumFixIts = 0; break; } - if (Hint.InsertionLoc.isValid() && Hint.InsertionLoc.isMacroID()) { + if (F->InsertionLoc.isValid() && F->InsertionLoc.isMacroID()) { NumFixIts = 0; break; } + + ++NumFixIts; } // Write the fix-its. WriteUnsigned(OS, NumFixIts); + for (fixit_iterator F = fixit_begin(), FEnd = fixit_end(); F != FEnd; ++F) { + WriteSourceLocation(OS, SM, F->RemoveRange.getBegin()); + WriteSourceLocation(OS, SM, F->RemoveRange.getEnd()); + WriteSourceLocation(OS, SM, F->InsertionLoc); + WriteString(OS, F->CodeToInsert); + } +} + +static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, + unsigned &Value) { + if (Memory + sizeof(unsigned) > MemoryEnd) + return true; + + memmove(&Value, Memory, sizeof(unsigned)); + Memory += sizeof(unsigned); + return false; +} + +static bool ReadSourceLocation(FileManager &FM, SourceManager &SM, + const char *&Memory, const char *MemoryEnd, + SourceLocation &Location) { + // Read the filename. + unsigned FileNameLen = 0; + if (ReadUnsigned(Memory, MemoryEnd, FileNameLen) || + Memory + FileNameLen > MemoryEnd) + return true; + + llvm::StringRef FileName(Memory, FileNameLen); + Memory += FileNameLen; + + // Read the line, column. + unsigned Line = 0, Column = 0; + if (ReadUnsigned(Memory, MemoryEnd, Line) || + ReadUnsigned(Memory, MemoryEnd, Column)) + return true; + + if (FileName.empty()) { + Location = SourceLocation(); + return false; + } + + const FileEntry *File = FM.getFile(FileName); + if (!File) + return true; + + // Make sure that this file has an entry in the source manager. + if (!SM.hasFileInfo(File)) + SM.createFileID(File, SourceLocation(), SrcMgr::C_User); + + Location = SM.getLocation(File, Line, Column); + return false; +} + +StoredDiagnostic +StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM, + const char *&Memory, const char *MemoryEnd) { + if (Memory == MemoryEnd) + return StoredDiagnostic(); + + // Read the severity level. + unsigned Level = 0; + if (ReadUnsigned(Memory, MemoryEnd, Level) || Level > Diagnostic::Fatal) + return StoredDiagnostic(); + + // Read the source location. + SourceLocation Location; + if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Location)) + return StoredDiagnostic(); + + // Read the diagnostic text. + if (Memory == MemoryEnd) + return StoredDiagnostic(); + + unsigned MessageLen = 0; + if (ReadUnsigned(Memory, MemoryEnd, MessageLen) || + Memory + MessageLen > MemoryEnd) + return StoredDiagnostic(); + + llvm::StringRef Message(Memory, MessageLen); + Memory += MessageLen; + + + // At this point, we have enough information to form a diagnostic. Do so. + StoredDiagnostic Diag; + Diag.Level = (Diagnostic::Level)Level; + Diag.Loc = FullSourceLoc(Location, SM); + Diag.Message = Message; + if (Memory == MemoryEnd) + return Diag; + + // Read the source ranges. + unsigned NumSourceRanges = 0; + if (ReadUnsigned(Memory, MemoryEnd, NumSourceRanges)) + return Diag; + for (unsigned I = 0; I != NumSourceRanges; ++I) { + SourceLocation Begin, End; + if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Begin) || + ReadSourceLocation(FM, SM, Memory, MemoryEnd, End)) + return Diag; + + Diag.Ranges.push_back(SourceRange(Begin, End)); + } + + // Read the fix-it hints. + unsigned NumFixIts = 0; + if (ReadUnsigned(Memory, MemoryEnd, NumFixIts)) + return Diag; for (unsigned I = 0; I != NumFixIts; ++I) { - const CodeModificationHint &Hint = getCodeModificationHint(I); - WriteSourceLocation(OS, SM, Hint.RemoveRange.getBegin()); - WriteSourceLocation(OS, SM, Hint.RemoveRange.getEnd()); - WriteSourceLocation(OS, SM, Hint.InsertionLoc); - WriteString(OS, Hint.CodeToInsert); + SourceLocation RemoveBegin, RemoveEnd, InsertionLoc; + unsigned InsertLen = 0; + if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveBegin) || + ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveEnd) || + ReadSourceLocation(FM, SM, Memory, MemoryEnd, InsertionLoc) || + ReadUnsigned(Memory, MemoryEnd, InsertLen) || + Memory + InsertLen > MemoryEnd) { + Diag.FixIts.clear(); + return Diag; + } + + CodeModificationHint Hint; + Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd); + Hint.InsertionLoc = InsertionLoc; + Hint.CodeToInsert.assign(Memory, Memory + InsertLen); + Memory += InsertLen; + Diag.FixIts.push_back(Hint); } + + return Diag; } /// IncludeInDiagnosticCounts - This method (whose default implementation diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index a0c4889c16..345b9ba4d3 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -90,8 +90,46 @@ public: } }; +class StoredDiagnosticClient : public DiagnosticClient { + llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags; + +public: + explicit StoredDiagnosticClient( + llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags) + : StoredDiags(StoredDiags) { } + + virtual void HandleDiagnostic(Diagnostic::Level Level, + const DiagnosticInfo &Info); +}; + +/// \brief RAII object that optionally captures diagnostics, if +/// there is no diagnostic client to capture them already. +class CaptureDroppedDiagnostics { + Diagnostic &Diags; + StoredDiagnosticClient Client; + DiagnosticClient *PreviousClient; + +public: + CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags, + llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags) + : Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient()) + { + if (RequestCapture || Diags.getClient() == 0) + Diags.setClient(&Client); + } + + ~CaptureDroppedDiagnostics() { + Diags.setClient(PreviousClient); + } +}; + } // anonymous namespace +void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level, + const DiagnosticInfo &Info) { + StoredDiags.push_back(StoredDiagnostic(Level, Info)); +} + const std::string &ASTUnit::getOriginalSourceFileName() { return OriginalSourceFile; } @@ -105,11 +143,16 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, Diagnostic &Diags, bool OnlyLocalDecls, RemappedFile *RemappedFiles, - unsigned NumRemappedFiles) { + unsigned NumRemappedFiles, + bool CaptureDiagnostics) { llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true)); AST->OnlyLocalDecls = OnlyLocalDecls; AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); + // If requested, capture diagnostics in the ASTUnit. + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, Diags, + AST->Diagnostics); + for (unsigned I = 0; I != NumRemappedFiles; ++I) { // Create the file entry for the file that we're mapping from. const FileEntry *FromFile @@ -231,7 +274,8 @@ public: ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, Diagnostic &Diags, - bool OnlyLocalDecls) { + bool OnlyLocalDecls, + bool CaptureDiagnostics) { // Create the compiler instance to use for building the AST. CompilerInstance Clang; llvm::OwningPtr<ASTUnit> AST; @@ -245,8 +289,13 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, // Create the target instance. Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), Clang.getTargetOpts())); - if (!Clang.hasTarget()) - goto error; + if (!Clang.hasTarget()) { + Clang.takeSourceManager(); + Clang.takeFileManager(); + Clang.takeDiagnosticClient(); + Clang.takeDiagnostics(); + return 0; + } // Inform the target of the language options. // @@ -261,10 +310,14 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, // Create the AST unit. AST.reset(new ASTUnit(false)); - AST->OnlyLocalDecls = OnlyLocalDecls; AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; + // Capture any diagnostics that would otherwise be dropped. + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, + Clang.getDiagnostics(), + AST->Diagnostics); + // Create a file manager object to provide access to and cache the filesystem. Clang.setFileManager(&AST->getFileManager()); @@ -312,7 +365,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, llvm::StringRef ResourceFilesPath, bool OnlyLocalDecls, RemappedFile *RemappedFiles, - unsigned NumRemappedFiles) { + unsigned NumRemappedFiles, + bool CaptureDiagnostics) { llvm::SmallVector<const char *, 16> Args; Args.push_back("<clang>"); // FIXME: Remove dummy argument. Args.insert(Args.end(), ArgBegin, ArgEnd); @@ -363,5 +417,6 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; CI->getFrontendOpts().DisableFree = true; - return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls); + return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls, + CaptureDiagnostics); } diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 917cbd711a..1831ca532b 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -102,7 +102,7 @@ namespace { void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info) { - Info.Serialize(DiagLevel, OS); + StoredDiagnostic(DiagLevel, Info).Serialize(OS); } static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, diff --git a/test/Index/cindex-on-invalid.m b/test/Index/cindex-on-invalid.m index 651c40a335..0f6bdffe91 100644 --- a/test/Index/cindex-on-invalid.m +++ b/test/Index/cindex-on-invalid.m @@ -1,5 +1,6 @@ // RUN: not c-index-test -test-load-source local %s > %t 2> %t.err // RUN: FileCheck %s < %t.err +// XFAIL: * // CHECK: error: expected identifier or '(' // CHECK: Unable to load translation unit! diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index 0b08874709..cb81988d95 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -933,9 +933,7 @@ void clang_setUseExternalASTGeneration(CXIndex CIdx, int value) { } CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx, - const char *ast_filename, - CXDiagnosticCallback diag_callback, - CXClientData diag_client_data) { + const char *ast_filename) { if (!CIdx) return 0; @@ -945,11 +943,9 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx, DiagnosticOptions DiagOpts; llvm::OwningPtr<Diagnostic> Diags; Diags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0)); - CIndexDiagnosticClient DiagClient(diag_callback, diag_client_data); - Diags->setClient(&DiagClient); - return ASTUnit::LoadFromPCHFile(ast_filename, *Diags, - CXXIdx->getOnlyLocalDecls()); + CXXIdx->getOnlyLocalDecls(), + 0, 0, true); } CXTranslationUnit @@ -958,9 +954,7 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, int num_command_line_args, const char **command_line_args, unsigned num_unsaved_files, - struct CXUnsavedFile *unsaved_files, - CXDiagnosticCallback diag_callback, - CXClientData diag_client_data) { + struct CXUnsavedFile *unsaved_files) { if (!CIdx) return 0; @@ -970,8 +964,6 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, DiagnosticOptions DiagOpts; llvm::OwningPtr<Diagnostic> Diags; Diags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0)); - CIndexDiagnosticClient DiagClient(diag_callback, diag_client_data); - Diags->setClient(&DiagClient); llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; for (unsigned I = 0; I != num_unsaved_files; ++I) { @@ -1006,7 +998,8 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(), RemappedFiles.data(), - RemappedFiles.size())); + RemappedFiles.size(), + /*CaptureDiagnostics=*/true)); // FIXME: Until we have broader testing, just drop the entire AST if we // encountered an error. @@ -1097,20 +1090,22 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg; } - // FIXME: Parse the (redirected) standard error to emit diagnostics. - ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, *Diags, CXXIdx->getOnlyLocalDecls(), RemappedFiles.data(), - RemappedFiles.size()); + RemappedFiles.size(), + /*CaptureDiagnostics=*/true); if (ATU) ATU->unlinkTemporaryFile(); // FIXME: Currently we don't report diagnostics on invalid ASTs. - if (ATU) - ReportSerializedDiagnostics(DiagnosticsFile, *Diags, - num_unsaved_files, unsaved_files, - ATU->getASTContext().getLangOptions()); + if (ATU) { + LoadSerializedDiagnostics(DiagnosticsFile, + num_unsaved_files, unsaved_files, + ATU->getFileManager(), + ATU->getSourceManager(), + ATU->getDiagnostics()); + } for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i) TemporaryFiles[i].eraseFromDisk(); diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index 2c738190b4..1c445b74aa 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -1,9 +1,12 @@ _clang_annotateTokens _clang_codeComplete +_clang_codeCompleteGetDiagnostic +_clang_codeCompleteGetNumDiagnostics _clang_createIndex _clang_createTranslationUnit _clang_createTranslationUnitFromSourceFile _clang_disposeCodeCompleteResults +_clang_disposeDiagnostic _clan |