Introduce serialization and deserialization of diagnostic information

so that CIndex can report diagnostics through the normal mechanisms
even when executing Clang in a separate process. This applies both
when performing code completion and when using ASTs as an intermediary
for clang_createTranslationUnitFromSourceFile().

The serialized format is not perfect at the moment, because it does
not encapsulate macro-instantiation information. Instead, it maps all
source locations back to the instantiation location. However, it does
maintain source-range and fix-it information. To get perfect fidelity
from the serialized format would require serializing a large chunk of
the source manager; at present, it isn't clear if this code will live
long enough for that to matter.

llvm-svn: 94740
This commit is contained in:
Douglas Gregor
2010-01-28 06:00:51 +00:00
parent fee0e96c82
commit ac0605e927
15 changed files with 391 additions and 10 deletions

View File

@@ -23,16 +23,19 @@
namespace llvm {
template <typename T> class SmallVectorImpl;
class raw_ostream;
}
namespace clang {
class DeclContext;
class DiagnosticBuilder;
class DiagnosticClient;
class FileManager;
class IdentifierInfo;
class LangOptions;
class PartialDiagnostic;
class Preprocessor;
class SourceManager;
class SourceRange;
// Import the diagnostic enums themselves.
@@ -400,6 +403,13 @@ 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
@@ -568,6 +578,9 @@ public:
/// been emitted.
~DiagnosticBuilder() { Emit(); }
/// isActive - Determine whether this diagnostic is still active.
bool isActive() const { return DiagObj != 0; }
/// Operator bool: conversion of DiagnosticBuilder to bool always returns
/// true. This allows is to be used in boolean error contexts like:
/// return Diag(...);
@@ -786,6 +799,12 @@ public:
/// output buffer using the arguments stored in this diagnostic.
void FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
llvm::SmallVectorImpl<char> &OutStr) const;
/// 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;
};
/// DiagnosticClient - This is an abstract interface implemented by clients of

View File

@@ -19,6 +19,8 @@ def err_fe_invalid_code_complete_file : Error<
"cannot locate code-completion file %0">, DefaultFatal;
def err_fe_stdout_binary : Error<"unable to change standard output to binary">,
DefaultFatal;
def err_fe_stderr_binary : Error<"unable to change standard error to binary">,
DefaultFatal;
def err_fe_dependency_file_requires_MT : Error<
"-dependency-file requires at least one -MT option">;
def err_fe_incompatible_options : Error<

View File

@@ -669,6 +669,9 @@ public:
::const_iterator fileinfo_iterator;
fileinfo_iterator fileinfo_begin() const { return FileInfos.begin(); }
fileinfo_iterator fileinfo_end() const { return FileInfos.end(); }
bool hasFileInfo(const FileEntry *File) const {
return FileInfos.find(File) != FileInfos.end();
}
/// PrintStats - Print statistics to stderr.
///

View File

@@ -165,6 +165,7 @@ def fno_caret_diagnostics : Flag<"-fno-caret-diagnostics">,
HelpText<"Do not include source line and caret with diagnostics">;
def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">,
HelpText<"Do not include fixit information in diagnostics">;
def fdiagnostics_binary : Flag<"-fdiagnostics-binary">;
def w : Flag<"-w">, HelpText<"Suppress all warnings">;
def pedantic : Flag<"-pedantic">;
def pedantic_errors : Flag<"-pedantic-errors">;

View File

@@ -252,6 +252,7 @@ def fconstant_string_class_EQ : Joined<"-fconstant-string-class=">, Group<f_Grou
def fcreate_profile : Flag<"-fcreate-profile">, Group<f_Group>;
def fdebug_pass_arguments : Flag<"-fdebug-pass-arguments">, Group<f_Group>;
def fdebug_pass_structure : Flag<"-fdebug-pass-structure">, Group<f_Group>;
def fdiagnostics_binary : Flag<"-fdiagnostics-binary">, Group<f_Group>, Flags<[HelpHidden]>;
def fdiagnostics_fixit_info : Flag<"-fdiagnostics-fixit-info">, Group<f_Group>;
def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, Group<f_Group>;
def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, Group<f_Group>;

View File

@@ -31,9 +31,12 @@ public:
unsigned ShowOptionNames : 1; /// Show the diagnostic name for mappable
/// diagnostics.
unsigned ShowColors : 1; /// Show diagnostics with ANSI color sequences.
unsigned VerifyDiagnostics; /// Check that diagnostics match the expected
unsigned VerifyDiagnostics: 1; /// Check that diagnostics match the expected
/// diagnostics, indicated by markers in the
/// input source file.
unsigned BinaryOutput : 1; /// Emit diagnostics via the diagnostic
/// binary serialization mechanism, to be
/// deserialized by, e.g., the CIndex library.
/// The distance between tab stops.
unsigned TabStop;
@@ -66,6 +69,7 @@ public:
ShowOptionNames = 0;
ShowSourceRanges = 0;
VerifyDiagnostics = 0;
BinaryOutput = 0;
}
};

View File

@@ -21,8 +21,10 @@
#include "clang/Analysis/AnalysisDiagnostic.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
@@ -385,6 +387,123 @@ 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;
@@ -917,6 +1036,104 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
}
}
static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) {
OS.write((const char *)&Value, sizeof(unsigned));
}
static void WriteString(llvm::raw_ostream &OS, llvm::StringRef String) {
WriteUnsigned(OS, String.size());
OS.write(String.data(), String.size());
}
static void WriteSourceLocation(llvm::raw_ostream &OS,
SourceManager *SM,
SourceLocation Location) {
if (!SM || Location.isInvalid()) {
// If we don't have a source manager or this location is invalid,
// just write an invalid location.
WriteUnsigned(OS, 0);
WriteUnsigned(OS, 0);
WriteUnsigned(OS, 0);
return;
}
Location = SM->getInstantiationLoc(Location);
std::pair<FileID, unsigned> Decomposed = SM->getDecomposedLoc(Location);
WriteString(OS, SM->getFileEntryForID(Decomposed.first)->getName());
WriteUnsigned(OS, SM->getLineNumber(Decomposed.first, Decomposed.second));
WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second));
}
void DiagnosticInfo::Serialize(Diagnostic::Level DiagLevel,
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);
WriteSourceLocation(OS, SM, getLocation());
// Write the diagnostic message.
llvm::SmallString<64> Message;
FormatDiagnostic(Message);
WriteString(OS, Message);
// 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())
continue;
++NumNonMacroRanges;
}
// 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())
continue;
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())) {
NumFixIts = 0;
break;
}
if (Hint.InsertionLoc.isValid() && Hint.InsertionLoc.isMacroID()) {
NumFixIts = 0;
break;
}
}
// Write the fix-its.
WriteUnsigned(OS, NumFixIts);
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);
}
}
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
/// DiagnosticClient should be included in the number of diagnostics

View File

@@ -1058,6 +1058,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_diagnostics_fixit_info))
CmdArgs.push_back("-fno-diagnostics-fixit-info");
if (Args.hasArg(options::OPT_fdiagnostics_binary))
CmdArgs.push_back("-fdiagnostics-binary");
// Enable -fdiagnostics-show-option by default.
if (Args.hasFlag(options::OPT_fdiagnostics_show_option,
options::OPT_fno_diagnostics_show_option))

View File

@@ -83,6 +83,23 @@ void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
}
// Diagnostics
namespace {
class BinaryDiagnosticSerializer : public DiagnosticClient {
llvm::raw_ostream &OS;
SourceManager *SourceMgr;
public:
explicit BinaryDiagnosticSerializer(llvm::raw_ostream &OS)
: OS(OS), SourceMgr(0) { }
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
const DiagnosticInfo &Info);
};
}
void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel,
const DiagnosticInfo &Info) {
Info.Serialize(DiagLevel, OS);
}
static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
unsigned argc, char **argv,
@@ -122,8 +139,23 @@ Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
// Create the diagnostic client for reporting errors or for
// implementing -verify.
llvm::OwningPtr<DiagnosticClient> DiagClient(
new TextDiagnosticPrinter(llvm::errs(), Opts));
llvm::OwningPtr<DiagnosticClient> DiagClient;
if (Opts.BinaryOutput) {
if (llvm::sys::Program::ChangeStderrToBinary()) {
// We weren't able to set standard error to binary, which is a
// bit of a problem. So, just create a text diagnostic printer
// to complain about this problem, and pretend that the user
// didn't try to use binary output.
DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
Diags->setClient(DiagClient.take());
Diags->Report(diag::err_fe_stderr_binary);
return Diags.take();
} else {
DiagClient.reset(new BinaryDiagnosticSerializer(llvm::errs()));
}
} else {
DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
}
// Chain in -verify checker, if requested.
if (Opts.VerifyDiagnostics)

View File

@@ -220,6 +220,8 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-fcolor-diagnostics");
if (Opts.VerifyDiagnostics)
Res.push_back("-verify");
if (Opts.BinaryOutput)
Res.push_back("-fdiagnostics-binary");
if (Opts.ShowOptionNames)
Res.push_back("-fdiagnostics-show-option");
if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) {
@@ -808,6 +810,7 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option);
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {

View File

@@ -0,0 +1,16 @@
_Complex cd; // CHECK: code-complete-errors.c:1:1: warning: plain '_Complex' requires a type specifier; assuming '_Complex double'
struct s {
int x, y;;
};
struct s s0 = { y: 5 }; // CHECK: code-complete-errors.c:7:20: warning: use of GNU old-style field designator extension
int f(int *ptr1, float *ptr2) {
return ptr1 != ptr2; // CHECK: code-complete-errors.c:10:15: warning: comparison of distinct pointer types ('int *' and 'float *')
}
void g() { }
// RUN: c-index-test -code-completion-at=%s:13:12 %s 2> %t
// RUN: FileCheck -check-prefix=CHECK %s < %t

View File

@@ -1044,6 +1044,13 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
argv.push_back(arg);
}
// Generate a temporary name for the diagnostics file.
char tmpFileResults[L_tmpnam];
char *tmpResultsFileName = tmpnam(tmpFileResults);
llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
TemporaryFiles.push_back(DiagnosticsFile);
argv.push_back("-fdiagnostics-binary");
// Add the null terminator.
argv.push_back(NULL);
@@ -1051,7 +1058,8 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
// on Unix or NUL (Windows).
std::string ErrMsg;
const llvm::sys::Path *Redirects[] = { &DevNull, &DevNull, &DevNull, NULL };
const llvm::sys::Path *Redirects[] = { &DevNull, &DevNull, &DiagnosticsFile,
NULL };
llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
/* redirects */ &Redirects[0],
/* secondsToWait */ 0, /* memoryLimits */ 0, &ErrMsg);
@@ -1078,6 +1086,9 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
if (ATU)
ATU->unlinkTemporaryFile();
ReportSerializedDiagnostics(DiagnosticsFile, *Diags,
num_unsaved_files, unsaved_files);
for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
TemporaryFiles[i].eraseFromDisk();

View File

@@ -231,7 +231,8 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
argv.push_back("-no-code-completion-debug-printer");
argv.push_back("-Xclang");
argv.push_back("-code-completion-macros");
argv.push_back("-fdiagnostics-binary");
// Remap any unsaved files to temporary files.
std::vector<std::string> RemapArgs;
if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
@@ -267,17 +268,24 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
// Add the null terminator.
argv.push_back(NULL);
// Generate a temporary name for the AST file.
// Generate a temporary name for the code-completion results file.
char tmpFile[L_tmpnam];
char *tmpFileName = tmpnam(tmpFile);
llvm::sys::Path ResultsFile(tmpFileName);
TemporaryFiles.push_back(ResultsFile);
// Generate a temporary name for the diagnostics file.
char tmpFileResults[L_tmpnam];
char *tmpResultsFileName = tmpnam(tmpFileResults);
llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
TemporaryFiles.push_back(DiagnosticsFile);
// Invoke 'clang'.
llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
// on Unix or NUL (Windows).
std::string ErrMsg;
const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile,
&DiagnosticsFile, 0 };
llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
/* redirects */ &Redirects[0],
/* secondsToWait */ 0,
@@ -331,7 +339,8 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
Results->Buffer = F;
}
// FIXME: Parse the (redirected) standard error to emit diagnostics.
ReportSerializedDiagnostics(DiagnosticsFile, *Diags,
num_unsaved_files, unsaved_files);
for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
TemporaryFiles[i].eraseFromDisk();

View File

@@ -14,6 +14,9 @@
#include "CIndexer.h"
#include "CXSourceLocation.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Support/MemoryBuffer.h"
using namespace clang;
using namespace clang::cxloc;
@@ -196,3 +199,47 @@ CXString clang_getDiagnosticFixItReplacement(CXDiagnostic Diag,
}
} // end extern "C"
void clang::ReportSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
Diagnostic &Diags,
unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files) {
using llvm::MemoryBuffer;
using llvm::StringRef;
MemoryBuffer *F = MemoryBuffer::getFile(DiagnosticsPath.c_str());
if (!F)
return;
// Enter the unsaved files into the file manager.
SourceManager SourceMgr;
FileManager FileMgr;
for (unsigned I = 0; I != num_unsaved_files; ++I) {
const FileEntry *File = FileMgr.getVirtualFile(unsaved_files[I].Filename,
unsaved_files[I].Length,
0);
if (!File) {
Diags.Report(diag::err_fe_remap_missing_from_file)
<< unsaved_files[I].Filename;
return;
}
MemoryBuffer *Buffer
= MemoryBuffer::getMemBuffer(unsaved_files[I].Contents,
unsaved_files[I].Contents + unsaved_files[I].Length);
if (!Buffer)
return;
SourceMgr.overrideFileContents(File, Buffer);
}
// Parse the diagnostics, emitting them one by one until we've
// exhausted the data.
StringRef Buffer = F->getBuffer();
const char *Memory = Buffer.data(), *MemoryEnd = Memory + Buffer.size();
while (Memory != MemoryEnd) {
DiagnosticBuilder DB = Diags.Deserialize(FileMgr, SourceMgr,
Memory, MemoryEnd);
if (!DB.isActive())
return;
}
}

View File

@@ -1,4 +1,4 @@
/*===-- CIndexDiagnostic.h - Diagnostics C Interface --------------*- C -*-===*\
/*===-- CIndexDiagnostic.h - Diagnostics C Interface ------------*- C++ -*-===*\
|* *|
|* The LLVM Compiler Infrastructure *|
|* *|
@@ -17,8 +17,13 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
namespace llvm { namespace sys {
class Path;
} }
namespace clang {
class Diagnostic;
class Preprocessor;
/**
@@ -43,7 +48,15 @@ public:
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
const DiagnosticInfo &Info);
};
/// \brief Given the path to a file that contains binary, serialized
/// diagnostics produced by Clang, emit those diagnostics via the
/// given diagnostic engine.
void ReportSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
Diagnostic &Diags,
unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files);
} // end namespace clang
#endif // LLVM_CLANG_CINDEX_DIAGNOSTIC_H