1f4a2713aSLionel Sambuc //===-- CXLoadedDiagnostic.cpp - Handling of persisent diags ----*- C++ -*-===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // Implements handling of persisent diagnostics.
11f4a2713aSLionel Sambuc //
12f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
13f4a2713aSLionel Sambuc 
14f4a2713aSLionel Sambuc #include "CXLoadedDiagnostic.h"
15f4a2713aSLionel Sambuc #include "CXString.h"
16f4a2713aSLionel Sambuc #include "clang/Basic/Diagnostic.h"
17f4a2713aSLionel Sambuc #include "clang/Basic/FileManager.h"
18*0a6a1f1dSLionel Sambuc #include "clang/Basic/LLVM.h"
19*0a6a1f1dSLionel Sambuc #include "clang/Frontend/SerializedDiagnosticReader.h"
20*0a6a1f1dSLionel Sambuc #include "clang/Frontend/SerializedDiagnostics.h"
21*0a6a1f1dSLionel Sambuc #include "llvm/ADT/Optional.h"
22f4a2713aSLionel Sambuc #include "llvm/ADT/StringRef.h"
23f4a2713aSLionel Sambuc #include "llvm/ADT/Twine.h"
24f4a2713aSLionel Sambuc #include "llvm/Bitcode/BitstreamReader.h"
25*0a6a1f1dSLionel Sambuc #include "llvm/Support/ErrorHandling.h"
26f4a2713aSLionel Sambuc #include "llvm/Support/MemoryBuffer.h"
27f4a2713aSLionel Sambuc using namespace clang;
28f4a2713aSLionel Sambuc 
29f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
30f4a2713aSLionel Sambuc // Extend CXDiagnosticSetImpl which contains strings for diagnostics.
31f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
32f4a2713aSLionel Sambuc 
33f4a2713aSLionel Sambuc typedef llvm::DenseMap<unsigned, const char *> Strings;
34f4a2713aSLionel Sambuc 
35f4a2713aSLionel Sambuc namespace {
36f4a2713aSLionel Sambuc class CXLoadedDiagnosticSetImpl : public CXDiagnosticSetImpl {
37f4a2713aSLionel Sambuc public:
CXLoadedDiagnosticSetImpl()38f4a2713aSLionel Sambuc   CXLoadedDiagnosticSetImpl() : CXDiagnosticSetImpl(true), FakeFiles(FO) {}
~CXLoadedDiagnosticSetImpl()39f4a2713aSLionel Sambuc   virtual ~CXLoadedDiagnosticSetImpl() {}
40f4a2713aSLionel Sambuc 
41f4a2713aSLionel Sambuc   llvm::BumpPtrAllocator Alloc;
42f4a2713aSLionel Sambuc   Strings Categories;
43f4a2713aSLionel Sambuc   Strings WarningFlags;
44f4a2713aSLionel Sambuc   Strings FileNames;
45f4a2713aSLionel Sambuc 
46f4a2713aSLionel Sambuc   FileSystemOptions FO;
47f4a2713aSLionel Sambuc   FileManager FakeFiles;
48f4a2713aSLionel Sambuc   llvm::DenseMap<unsigned, const FileEntry *> Files;
49f4a2713aSLionel Sambuc 
50f4a2713aSLionel Sambuc   /// \brief Copy the string into our own allocator.
copyString(StringRef Blob)51f4a2713aSLionel Sambuc   const char *copyString(StringRef Blob) {
52f4a2713aSLionel Sambuc     char *mem = Alloc.Allocate<char>(Blob.size() + 1);
53f4a2713aSLionel Sambuc     memcpy(mem, Blob.data(), Blob.size());
54f4a2713aSLionel Sambuc     mem[Blob.size()] = '\0';
55f4a2713aSLionel Sambuc     return mem;
56f4a2713aSLionel Sambuc   }
57f4a2713aSLionel Sambuc };
58f4a2713aSLionel Sambuc }
59f4a2713aSLionel Sambuc 
60f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
61f4a2713aSLionel Sambuc // Cleanup.
62f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
63f4a2713aSLionel Sambuc 
~CXLoadedDiagnostic()64f4a2713aSLionel Sambuc CXLoadedDiagnostic::~CXLoadedDiagnostic() {}
65f4a2713aSLionel Sambuc 
66f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
67f4a2713aSLionel Sambuc // Public CXLoadedDiagnostic methods.
68f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
69f4a2713aSLionel Sambuc 
getSeverity() const70f4a2713aSLionel Sambuc CXDiagnosticSeverity CXLoadedDiagnostic::getSeverity() const {
71*0a6a1f1dSLionel Sambuc   // FIXME: Fail more softly if the diagnostic level is unknown?
72*0a6a1f1dSLionel Sambuc   auto severityAsLevel = static_cast<serialized_diags::Level>(severity);
73*0a6a1f1dSLionel Sambuc   assert(severity == static_cast<unsigned>(severityAsLevel) &&
74*0a6a1f1dSLionel Sambuc          "unknown serialized diagnostic level");
75*0a6a1f1dSLionel Sambuc 
76*0a6a1f1dSLionel Sambuc   switch (severityAsLevel) {
77*0a6a1f1dSLionel Sambuc #define CASE(X) case serialized_diags::X: return CXDiagnostic_##X;
78*0a6a1f1dSLionel Sambuc   CASE(Ignored)
79*0a6a1f1dSLionel Sambuc   CASE(Note)
80*0a6a1f1dSLionel Sambuc   CASE(Warning)
81*0a6a1f1dSLionel Sambuc   CASE(Error)
82*0a6a1f1dSLionel Sambuc   CASE(Fatal)
83*0a6a1f1dSLionel Sambuc #undef CASE
84*0a6a1f1dSLionel Sambuc   // The 'Remark' level isn't represented in the stable API.
85*0a6a1f1dSLionel Sambuc   case serialized_diags::Remark: return CXDiagnostic_Warning;
86f4a2713aSLionel Sambuc   }
87f4a2713aSLionel Sambuc 
88f4a2713aSLionel Sambuc   llvm_unreachable("Invalid diagnostic level");
89f4a2713aSLionel Sambuc }
90f4a2713aSLionel Sambuc 
makeLocation(const CXLoadedDiagnostic::Location * DLoc)91f4a2713aSLionel Sambuc static CXSourceLocation makeLocation(const CXLoadedDiagnostic::Location *DLoc) {
92f4a2713aSLionel Sambuc   // The lowest bit of ptr_data[0] is always set to 1 to indicate this
93f4a2713aSLionel Sambuc   // is a persistent diagnostic.
94f4a2713aSLionel Sambuc   uintptr_t V = (uintptr_t) DLoc;
95f4a2713aSLionel Sambuc   V |= 0x1;
96*0a6a1f1dSLionel Sambuc   CXSourceLocation Loc = { {  (void*) V, nullptr }, 0 };
97f4a2713aSLionel Sambuc   return Loc;
98f4a2713aSLionel Sambuc }
99f4a2713aSLionel Sambuc 
getLocation() const100f4a2713aSLionel Sambuc CXSourceLocation CXLoadedDiagnostic::getLocation() const {
101f4a2713aSLionel Sambuc   // The lowest bit of ptr_data[0] is always set to 1 to indicate this
102f4a2713aSLionel Sambuc   // is a persistent diagnostic.
103f4a2713aSLionel Sambuc   return makeLocation(&DiagLoc);
104f4a2713aSLionel Sambuc }
105f4a2713aSLionel Sambuc 
getSpelling() const106f4a2713aSLionel Sambuc CXString CXLoadedDiagnostic::getSpelling() const {
107f4a2713aSLionel Sambuc   return cxstring::createRef(Spelling);
108f4a2713aSLionel Sambuc }
109f4a2713aSLionel Sambuc 
getDiagnosticOption(CXString * Disable) const110f4a2713aSLionel Sambuc CXString CXLoadedDiagnostic::getDiagnosticOption(CXString *Disable) const {
111f4a2713aSLionel Sambuc   if (DiagOption.empty())
112f4a2713aSLionel Sambuc     return cxstring::createEmpty();
113f4a2713aSLionel Sambuc 
114f4a2713aSLionel Sambuc   // FIXME: possibly refactor with logic in CXStoredDiagnostic.
115f4a2713aSLionel Sambuc   if (Disable)
116f4a2713aSLionel Sambuc     *Disable = cxstring::createDup((Twine("-Wno-") + DiagOption).str());
117f4a2713aSLionel Sambuc   return cxstring::createDup((Twine("-W") + DiagOption).str());
118f4a2713aSLionel Sambuc }
119f4a2713aSLionel Sambuc 
getCategory() const120f4a2713aSLionel Sambuc unsigned CXLoadedDiagnostic::getCategory() const {
121f4a2713aSLionel Sambuc   return category;
122f4a2713aSLionel Sambuc }
123f4a2713aSLionel Sambuc 
getCategoryText() const124f4a2713aSLionel Sambuc CXString CXLoadedDiagnostic::getCategoryText() const {
125f4a2713aSLionel Sambuc   return cxstring::createDup(CategoryText);
126f4a2713aSLionel Sambuc }
127f4a2713aSLionel Sambuc 
getNumRanges() const128f4a2713aSLionel Sambuc unsigned CXLoadedDiagnostic::getNumRanges() const {
129f4a2713aSLionel Sambuc   return Ranges.size();
130f4a2713aSLionel Sambuc }
131f4a2713aSLionel Sambuc 
getRange(unsigned Range) const132f4a2713aSLionel Sambuc CXSourceRange CXLoadedDiagnostic::getRange(unsigned Range) const {
133f4a2713aSLionel Sambuc   assert(Range < Ranges.size());
134f4a2713aSLionel Sambuc   return Ranges[Range];
135f4a2713aSLionel Sambuc }
136f4a2713aSLionel Sambuc 
getNumFixIts() const137f4a2713aSLionel Sambuc unsigned CXLoadedDiagnostic::getNumFixIts() const {
138f4a2713aSLionel Sambuc   return FixIts.size();
139f4a2713aSLionel Sambuc }
140f4a2713aSLionel Sambuc 
getFixIt(unsigned FixIt,CXSourceRange * ReplacementRange) const141f4a2713aSLionel Sambuc CXString CXLoadedDiagnostic::getFixIt(unsigned FixIt,
142f4a2713aSLionel Sambuc                                       CXSourceRange *ReplacementRange) const {
143f4a2713aSLionel Sambuc   assert(FixIt < FixIts.size());
144f4a2713aSLionel Sambuc   if (ReplacementRange)
145f4a2713aSLionel Sambuc     *ReplacementRange = FixIts[FixIt].first;
146f4a2713aSLionel Sambuc   return cxstring::createRef(FixIts[FixIt].second);
147f4a2713aSLionel Sambuc }
148f4a2713aSLionel Sambuc 
decodeLocation(CXSourceLocation location,CXFile * file,unsigned int * line,unsigned int * column,unsigned int * offset)149f4a2713aSLionel Sambuc void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location,
150f4a2713aSLionel Sambuc                                         CXFile *file,
151f4a2713aSLionel Sambuc                                         unsigned int *line,
152f4a2713aSLionel Sambuc                                         unsigned int *column,
153f4a2713aSLionel Sambuc                                         unsigned int *offset) {
154f4a2713aSLionel Sambuc 
155f4a2713aSLionel Sambuc 
156f4a2713aSLionel Sambuc   // CXSourceLocation consists of the following fields:
157f4a2713aSLionel Sambuc   //
158f4a2713aSLionel Sambuc   //   void *ptr_data[2];
159f4a2713aSLionel Sambuc   //   unsigned int_data;
160f4a2713aSLionel Sambuc   //
161f4a2713aSLionel Sambuc   // The lowest bit of ptr_data[0] is always set to 1 to indicate this
162f4a2713aSLionel Sambuc   // is a persistent diagnostic.
163f4a2713aSLionel Sambuc   //
164f4a2713aSLionel Sambuc   // For now, do the unoptimized approach and store the data in a side
165f4a2713aSLionel Sambuc   // data structure.  We can optimize this case later.
166f4a2713aSLionel Sambuc 
167f4a2713aSLionel Sambuc   uintptr_t V = (uintptr_t) location.ptr_data[0];
168f4a2713aSLionel Sambuc   assert((V & 0x1) == 1);
169f4a2713aSLionel Sambuc   V &= ~(uintptr_t)1;
170f4a2713aSLionel Sambuc 
171f4a2713aSLionel Sambuc   const Location &Loc = *((Location*)V);
172f4a2713aSLionel Sambuc 
173f4a2713aSLionel Sambuc   if (file)
174f4a2713aSLionel Sambuc     *file = Loc.file;
175f4a2713aSLionel Sambuc   if (line)
176f4a2713aSLionel Sambuc     *line = Loc.line;
177f4a2713aSLionel Sambuc   if (column)
178f4a2713aSLionel Sambuc     *column = Loc.column;
179f4a2713aSLionel Sambuc   if (offset)
180f4a2713aSLionel Sambuc     *offset = Loc.offset;
181f4a2713aSLionel Sambuc }
182f4a2713aSLionel Sambuc 
183f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
184f4a2713aSLionel Sambuc // Deserialize diagnostics.
185f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
186f4a2713aSLionel Sambuc 
187f4a2713aSLionel Sambuc namespace {
188*0a6a1f1dSLionel Sambuc class DiagLoader : serialized_diags::SerializedDiagnosticReader {
189f4a2713aSLionel Sambuc   enum CXLoadDiag_Error *error;
190f4a2713aSLionel Sambuc   CXString *errorString;
191*0a6a1f1dSLionel Sambuc   std::unique_ptr<CXLoadedDiagnosticSetImpl> TopDiags;
192*0a6a1f1dSLionel Sambuc   SmallVector<std::unique_ptr<CXLoadedDiagnostic>, 8> CurrentDiags;
193f4a2713aSLionel Sambuc 
reportBad(enum CXLoadDiag_Error code,llvm::StringRef err)194*0a6a1f1dSLionel Sambuc   std::error_code reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
195f4a2713aSLionel Sambuc     if (error)
196f4a2713aSLionel Sambuc       *error = code;
197f4a2713aSLionel Sambuc     if (errorString)
198f4a2713aSLionel Sambuc       *errorString = cxstring::createDup(err);
199*0a6a1f1dSLionel Sambuc     return serialized_diags::SDError::HandlerFailed;
200f4a2713aSLionel Sambuc   }
201f4a2713aSLionel Sambuc 
reportInvalidFile(llvm::StringRef err)202*0a6a1f1dSLionel Sambuc   std::error_code reportInvalidFile(llvm::StringRef err) {
203f4a2713aSLionel Sambuc     return reportBad(CXLoadDiag_InvalidFile, err);
204f4a2713aSLionel Sambuc   }
205f4a2713aSLionel Sambuc 
206*0a6a1f1dSLionel Sambuc   std::error_code readRange(const serialized_diags::Location &SDStart,
207*0a6a1f1dSLionel Sambuc                             const serialized_diags::Location &SDEnd,
208f4a2713aSLionel Sambuc                             CXSourceRange &SR);
209f4a2713aSLionel Sambuc 
210*0a6a1f1dSLionel Sambuc   std::error_code readLocation(const serialized_diags::Location &SDLoc,
211*0a6a1f1dSLionel Sambuc                                CXLoadedDiagnostic::Location &LoadedLoc);
212*0a6a1f1dSLionel Sambuc 
213*0a6a1f1dSLionel Sambuc protected:
214*0a6a1f1dSLionel Sambuc   std::error_code visitStartOfDiagnostic() override;
215*0a6a1f1dSLionel Sambuc   std::error_code visitEndOfDiagnostic() override;
216*0a6a1f1dSLionel Sambuc 
217*0a6a1f1dSLionel Sambuc   std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override;
218*0a6a1f1dSLionel Sambuc 
219*0a6a1f1dSLionel Sambuc   std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) override;
220*0a6a1f1dSLionel Sambuc 
221*0a6a1f1dSLionel Sambuc   std::error_code visitDiagnosticRecord(
222*0a6a1f1dSLionel Sambuc       unsigned Severity, const serialized_diags::Location &Location,
223*0a6a1f1dSLionel Sambuc       unsigned Category, unsigned Flag, StringRef Message) override;
224*0a6a1f1dSLionel Sambuc 
225*0a6a1f1dSLionel Sambuc   std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
226*0a6a1f1dSLionel Sambuc                                       unsigned Timestamp,
227*0a6a1f1dSLionel Sambuc                                       StringRef Name) override;
228*0a6a1f1dSLionel Sambuc 
229*0a6a1f1dSLionel Sambuc   std::error_code visitFixitRecord(const serialized_diags::Location &Start,
230*0a6a1f1dSLionel Sambuc                                    const serialized_diags::Location &End,
231*0a6a1f1dSLionel Sambuc                                    StringRef CodeToInsert) override;
232*0a6a1f1dSLionel Sambuc 
233*0a6a1f1dSLionel Sambuc   std::error_code
234*0a6a1f1dSLionel Sambuc   visitSourceRangeRecord(const serialized_diags::Location &Start,
235*0a6a1f1dSLionel Sambuc                          const serialized_diags::Location &End) override;
236f4a2713aSLionel Sambuc 
237f4a2713aSLionel Sambuc public:
DiagLoader(enum CXLoadDiag_Error * e,CXString * es)238f4a2713aSLionel Sambuc   DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
239*0a6a1f1dSLionel Sambuc       : SerializedDiagnosticReader(), error(e), errorString(es) {
240f4a2713aSLionel Sambuc     if (error)
241f4a2713aSLionel Sambuc       *error = CXLoadDiag_None;
242f4a2713aSLionel Sambuc     if (errorString)
243f4a2713aSLionel Sambuc       *errorString = cxstring::createEmpty();
244f4a2713aSLionel Sambuc   }
245f4a2713aSLionel Sambuc 
246f4a2713aSLionel Sambuc   CXDiagnosticSet load(const char *file);
247f4a2713aSLionel Sambuc };
248f4a2713aSLionel Sambuc }
249f4a2713aSLionel Sambuc 
load(const char * file)250f4a2713aSLionel Sambuc CXDiagnosticSet DiagLoader::load(const char *file) {
251*0a6a1f1dSLionel Sambuc   TopDiags = llvm::make_unique<CXLoadedDiagnosticSetImpl>();
252f4a2713aSLionel Sambuc 
253*0a6a1f1dSLionel Sambuc   std::error_code EC = readDiagnostics(file);
254*0a6a1f1dSLionel Sambuc   if (EC) {
255*0a6a1f1dSLionel Sambuc     switch (EC.value()) {
256*0a6a1f1dSLionel Sambuc     case static_cast<int>(serialized_diags::SDError::HandlerFailed):
257*0a6a1f1dSLionel Sambuc       // We've already reported the problem.
258f4a2713aSLionel Sambuc       break;
259*0a6a1f1dSLionel Sambuc     case static_cast<int>(serialized_diags::SDError::CouldNotLoad):
260*0a6a1f1dSLionel Sambuc       reportBad(CXLoadDiag_CannotLoad, EC.message());
261f4a2713aSLionel Sambuc       break;
262f4a2713aSLionel Sambuc     default:
263*0a6a1f1dSLionel Sambuc       reportInvalidFile(EC.message());
264*0a6a1f1dSLionel Sambuc       break;
265*0a6a1f1dSLionel Sambuc     }
266f4a2713aSLionel Sambuc     return 0;
267f4a2713aSLionel Sambuc   }
268*0a6a1f1dSLionel Sambuc 
269*0a6a1f1dSLionel Sambuc   return (CXDiagnosticSet)TopDiags.release();
270f4a2713aSLionel Sambuc }
271f4a2713aSLionel Sambuc 
272*0a6a1f1dSLionel Sambuc std::error_code
readLocation(const serialized_diags::Location & SDLoc,CXLoadedDiagnostic::Location & LoadedLoc)273*0a6a1f1dSLionel Sambuc DiagLoader::readLocation(const serialized_diags::Location &SDLoc,
274*0a6a1f1dSLionel Sambuc                          CXLoadedDiagnostic::Location &LoadedLoc) {
275*0a6a1f1dSLionel Sambuc   unsigned FileID = SDLoc.FileID;
276*0a6a1f1dSLionel Sambuc   if (FileID == 0)
277*0a6a1f1dSLionel Sambuc     LoadedLoc.file = nullptr;
278*0a6a1f1dSLionel Sambuc   else {
279*0a6a1f1dSLionel Sambuc     LoadedLoc.file = const_cast<FileEntry *>(TopDiags->Files[FileID]);
280*0a6a1f1dSLionel Sambuc     if (!LoadedLoc.file)
281*0a6a1f1dSLionel Sambuc       return reportInvalidFile("Corrupted file entry in source location");
282f4a2713aSLionel Sambuc   }
283*0a6a1f1dSLionel Sambuc   LoadedLoc.line = SDLoc.Line;
284*0a6a1f1dSLionel Sambuc   LoadedLoc.column = SDLoc.Col;
285*0a6a1f1dSLionel Sambuc   LoadedLoc.offset = SDLoc.Offset;
286*0a6a1f1dSLionel Sambuc   return std::error_code();
287f4a2713aSLionel Sambuc }
288f4a2713aSLionel Sambuc 
289*0a6a1f1dSLionel Sambuc std::error_code
readRange(const serialized_diags::Location & SDStart,const serialized_diags::Location & SDEnd,CXSourceRange & SR)290*0a6a1f1dSLionel Sambuc DiagLoader::readRange(const serialized_diags::Location &SDStart,
291*0a6a1f1dSLionel Sambuc                       const serialized_diags::Location &SDEnd,
292f4a2713aSLionel Sambuc                       CXSourceRange &SR) {
293f4a2713aSLionel Sambuc   CXLoadedDiagnostic::Location *Start, *End;
294*0a6a1f1dSLionel Sambuc   Start = TopDiags->Alloc.Allocate<CXLoadedDiagnostic::Location>();
295*0a6a1f1dSLionel Sambuc   End = TopDiags->Alloc.Allocate<CXLoadedDiagnostic::Location>();
296f4a2713aSLionel Sambuc 
297*0a6a1f1dSLionel Sambuc   std::error_code EC;
298*0a6a1f1dSLionel Sambuc   if ((EC = readLocation(SDStart, *Start)))
299*0a6a1f1dSLionel Sambuc     return EC;
300*0a6a1f1dSLionel Sambuc   if ((EC = readLocation(SDEnd, *End)))
301*0a6a1f1dSLionel Sambuc     return EC;
302f4a2713aSLionel Sambuc 
303f4a2713aSLionel Sambuc   CXSourceLocation startLoc = makeLocation(Start);
304f4a2713aSLionel Sambuc   CXSourceLocation endLoc = makeLocation(End);
305f4a2713aSLionel Sambuc   SR = clang_getRange(startLoc, endLoc);
306*0a6a1f1dSLionel Sambuc   return std::error_code();
307f4a2713aSLionel Sambuc }
308f4a2713aSLionel Sambuc 
visitStartOfDiagnostic()309*0a6a1f1dSLionel Sambuc std::error_code DiagLoader::visitStartOfDiagnostic() {
310*0a6a1f1dSLionel Sambuc   CurrentDiags.push_back(llvm::make_unique<CXLoadedDiagnostic>());
311*0a6a1f1dSLionel Sambuc   return std::error_code();
312f4a2713aSLionel Sambuc }
313f4a2713aSLionel Sambuc 
visitEndOfDiagnostic()314*0a6a1f1dSLionel Sambuc std::error_code DiagLoader::visitEndOfDiagnostic() {
315*0a6a1f1dSLionel Sambuc   auto D = CurrentDiags.pop_back_val();
316*0a6a1f1dSLionel Sambuc   if (CurrentDiags.empty())
317*0a6a1f1dSLionel Sambuc     TopDiags->appendDiagnostic(std::move(D));
318*0a6a1f1dSLionel Sambuc   else
319*0a6a1f1dSLionel Sambuc     CurrentDiags.back()->getChildDiagnostics().appendDiagnostic(std::move(D));
320*0a6a1f1dSLionel Sambuc   return std::error_code();
321f4a2713aSLionel Sambuc }
322f4a2713aSLionel Sambuc 
visitCategoryRecord(unsigned ID,StringRef Name)323*0a6a1f1dSLionel Sambuc std::error_code DiagLoader::visitCategoryRecord(unsigned ID, StringRef Name) {
324*0a6a1f1dSLionel Sambuc   // FIXME: Why do we care about long strings?
325*0a6a1f1dSLionel Sambuc   if (Name.size() > 65536)
326*0a6a1f1dSLionel Sambuc     return reportInvalidFile("Out-of-bounds string in category");
327*0a6a1f1dSLionel Sambuc   TopDiags->Categories[ID] = TopDiags->copyString(Name);
328*0a6a1f1dSLionel Sambuc   return std::error_code();
329f4a2713aSLionel Sambuc }
330f4a2713aSLionel Sambuc 
visitDiagFlagRecord(unsigned ID,StringRef Name)331*0a6a1f1dSLionel Sambuc std::error_code DiagLoader::visitDiagFlagRecord(unsigned ID, StringRef Name) {
332*0a6a1f1dSLionel Sambuc   // FIXME: Why do we care about long strings?
333*0a6a1f1dSLionel Sambuc   if (Name.size() > 65536)
334*0a6a1f1dSLionel Sambuc     return reportInvalidFile("Out-of-bounds string in warning flag");
335*0a6a1f1dSLionel Sambuc   TopDiags->WarningFlags[ID] = TopDiags->copyString(Name);
336*0a6a1f1dSLionel Sambuc   return std::error_code();
337f4a2713aSLionel Sambuc }
338f4a2713aSLionel Sambuc 
visitFilenameRecord(unsigned ID,unsigned Size,unsigned Timestamp,StringRef Name)339*0a6a1f1dSLionel Sambuc std::error_code DiagLoader::visitFilenameRecord(unsigned ID, unsigned Size,
340*0a6a1f1dSLionel Sambuc                                                 unsigned Timestamp,
341*0a6a1f1dSLionel Sambuc                                                 StringRef Name) {
342*0a6a1f1dSLionel Sambuc   // FIXME: Why do we care about long strings?
343*0a6a1f1dSLionel Sambuc   if (Name.size() > 65536)
344*0a6a1f1dSLionel Sambuc     return reportInvalidFile("Out-of-bounds string in filename");
345*0a6a1f1dSLionel Sambuc   TopDiags->FileNames[ID] = TopDiags->copyString(Name);
346*0a6a1f1dSLionel Sambuc   TopDiags->Files[ID] =
347*0a6a1f1dSLionel Sambuc       TopDiags->FakeFiles.getVirtualFile(Name, Size, Timestamp);
348*0a6a1f1dSLionel Sambuc   return std::error_code();
349f4a2713aSLionel Sambuc }
350f4a2713aSLionel Sambuc 
351*0a6a1f1dSLionel Sambuc std::error_code
visitSourceRangeRecord(const serialized_diags::Location & Start,const serialized_diags::Location & End)352*0a6a1f1dSLionel Sambuc DiagLoader::visitSourceRangeRecord(const serialized_diags::Location &Start,
353*0a6a1f1dSLionel Sambuc                                    const serialized_diags::Location &End) {
354f4a2713aSLionel Sambuc   CXSourceRange SR;
355*0a6a1f1dSLionel Sambuc   if (std::error_code EC = readRange(Start, End, SR))
356*0a6a1f1dSLionel Sambuc     return EC;
357*0a6a1f1dSLionel Sambuc   CurrentDiags.back()->Ranges.push_back(SR);
358*0a6a1f1dSLionel Sambuc   return std::error_code();
359f4a2713aSLionel Sambuc }
360f4a2713aSLionel Sambuc 
361*0a6a1f1dSLionel Sambuc std::error_code
visitFixitRecord(const serialized_diags::Location & Start,const serialized_diags::Location & End,StringRef CodeToInsert)362*0a6a1f1dSLionel Sambuc DiagLoader::visitFixitRecord(const serialized_diags::Location &Start,
363*0a6a1f1dSLionel Sambuc                              const serialized_diags::Location &End,
364*0a6a1f1dSLionel Sambuc                              StringRef CodeToInsert) {
365f4a2713aSLionel Sambuc   CXSourceRange SR;
366*0a6a1f1dSLionel Sambuc   if (std::error_code EC = readRange(Start, End, SR))
367*0a6a1f1dSLionel Sambuc     return EC;
368*0a6a1f1dSLionel Sambuc   // FIXME: Why do we care about long strings?
369*0a6a1f1dSLionel Sambuc   if (CodeToInsert.size() > 65536)
370*0a6a1f1dSLionel Sambuc     return reportInvalidFile("Out-of-bounds string in FIXIT");
371*0a6a1f1dSLionel Sambuc   CurrentDiags.back()->FixIts.push_back(
372*0a6a1f1dSLionel Sambuc       std::make_pair(SR, TopDiags->copyString(CodeToInsert)));
373*0a6a1f1dSLionel Sambuc   return std::error_code();
374f4a2713aSLionel Sambuc }
375f4a2713aSLionel Sambuc 
visitDiagnosticRecord(unsigned Severity,const serialized_diags::Location & Location,unsigned Category,unsigned Flag,StringRef Message)376*0a6a1f1dSLionel Sambuc std::error_code DiagLoader::visitDiagnosticRecord(
377*0a6a1f1dSLionel Sambuc     unsigned Severity, const serialized_diags::Location &Location,
378*0a6a1f1dSLionel Sambuc     unsigned Category, unsigned Flag, StringRef Message) {
379*0a6a1f1dSLionel Sambuc   CXLoadedDiagnostic &D = *CurrentDiags.back();
380*0a6a1f1dSLionel Sambuc   D.severity = Severity;
381*0a6a1f1dSLionel Sambuc   if (std::error_code EC = readLocation(Location, D.DiagLoc))
382*0a6a1f1dSLionel Sambuc     return EC;
383*0a6a1f1dSLionel Sambuc   D.category = Category;
384*0a6a1f1dSLionel Sambuc   D.DiagOption = Flag ? TopDiags->WarningFlags[Flag] : "";
385*0a6a1f1dSLionel Sambuc   D.CategoryText = Category ? TopDiags->Categories[Category] : "";
386*0a6a1f1dSLionel Sambuc   D.Spelling = TopDiags->copyString(Message);
387*0a6a1f1dSLionel Sambuc   return std::error_code();
388f4a2713aSLionel Sambuc }
389f4a2713aSLionel Sambuc 
390f4a2713aSLionel Sambuc extern "C" {
clang_loadDiagnostics(const char * file,enum CXLoadDiag_Error * error,CXString * errorString)391f4a2713aSLionel Sambuc CXDiagnosticSet clang_loadDiagnostics(const char *file,
392f4a2713aSLionel Sambuc                                       enum CXLoadDiag_Error *error,
393f4a2713aSLionel Sambuc                                       CXString *errorString) {
394f4a2713aSLionel Sambuc   DiagLoader L(error, errorString);
395f4a2713aSLionel Sambuc   return L.load(file);
396f4a2713aSLionel Sambuc }
397f4a2713aSLionel Sambuc } // end extern 'C'.
398