blob: b89080f0991d28ccb54892edd1d2f06c597e7e47 [file] [log] [blame]
Chris Lattner2815bc92013-01-19 18:47:35 +00001//===-- CXLoadedDiagnostic.cpp - Handling of persisent diags ----*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Implements handling of persisent diagnostics.
11//
12//===----------------------------------------------------------------------===//
Ted Kremenek15322172011-11-10 08:43:12 +000013
14#include "CXLoadedDiagnostic.h"
15#include "CXString.h"
16#include "clang/Basic/Diagnostic.h"
17#include "clang/Basic/FileManager.h"
18#include "clang/Frontend/SerializedDiagnosticPrinter.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/ADT/Twine.h"
21#include "llvm/ADT/Optional.h"
22#include "clang/Basic/LLVM.h"
23#include "llvm/Support/ErrorHandling.h"
24#include "llvm/Bitcode/BitstreamReader.h"
25#include "llvm/Support/MemoryBuffer.h"
Ted Kremenek15322172011-11-10 08:43:12 +000026using namespace clang;
Ted Kremenek15322172011-11-10 08:43:12 +000027
28//===----------------------------------------------------------------------===//
29// Extend CXDiagnosticSetImpl which contains strings for diagnostics.
30//===----------------------------------------------------------------------===//
31
32typedef llvm::DenseMap<unsigned, llvm::StringRef> Strings;
33
34namespace {
35class CXLoadedDiagnosticSetImpl : public CXDiagnosticSetImpl {
36public:
37 CXLoadedDiagnosticSetImpl() : CXDiagnosticSetImpl(true), FakeFiles(FO) {}
38 virtual ~CXLoadedDiagnosticSetImpl() {}
39
Ted Kremenek15322172011-11-10 08:43:12 +000040 llvm::BumpPtrAllocator Alloc;
41 Strings Categories;
42 Strings WarningFlags;
43 Strings FileNames;
44
45 FileSystemOptions FO;
46 FileManager FakeFiles;
47 llvm::DenseMap<unsigned, const FileEntry *> Files;
Chris Lattnerb3ce3572013-01-20 02:38:54 +000048
49 llvm::StringRef makeString(StringRef Blob) {
50 char *mem = Alloc.Allocate<char>(Blob.size() + 1);
51 memcpy(mem, Blob.data(), Blob.size());
52 // Add a null terminator for those clients accessing the buffer
53 // like a c-string.
54 mem[Blob.size()] = '\0';
55 return llvm::StringRef(mem, Blob.size());
56 }
Ted Kremenek15322172011-11-10 08:43:12 +000057};
58}
59
Ted Kremenek15322172011-11-10 08:43:12 +000060//===----------------------------------------------------------------------===//
61// Cleanup.
62//===----------------------------------------------------------------------===//
63
64CXLoadedDiagnostic::~CXLoadedDiagnostic() {}
65
66//===----------------------------------------------------------------------===//
67// Public CXLoadedDiagnostic methods.
68//===----------------------------------------------------------------------===//
69
70CXDiagnosticSeverity CXLoadedDiagnostic::getSeverity() const {
71 // FIXME: possibly refactor with logic in CXStoredDiagnostic.
72 switch (severity) {
73 case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored;
74 case DiagnosticsEngine::Note: return CXDiagnostic_Note;
75 case DiagnosticsEngine::Warning: return CXDiagnostic_Warning;
76 case DiagnosticsEngine::Error: return CXDiagnostic_Error;
77 case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal;
78 }
79
80 llvm_unreachable("Invalid diagnostic level");
Ted Kremenek15322172011-11-10 08:43:12 +000081}
82
83static CXSourceLocation makeLocation(const CXLoadedDiagnostic::Location *DLoc) {
84 // The lowest bit of ptr_data[0] is always set to 1 to indicate this
85 // is a persistent diagnostic.
86 uintptr_t V = (uintptr_t) DLoc;
87 V |= 0x1;
88 CXSourceLocation Loc = { { (void*) V, 0 }, 0 };
89 return Loc;
90}
91
92CXSourceLocation CXLoadedDiagnostic::getLocation() const {
93 // The lowest bit of ptr_data[0] is always set to 1 to indicate this
94 // is a persistent diagnostic.
95 return makeLocation(&DiagLoc);
96}
97
98CXString CXLoadedDiagnostic::getSpelling() const {
Dmitri Gribenko5595ded2013-02-02 02:19:29 +000099 return cxstring::createRef(Spelling);
Ted Kremenek15322172011-11-10 08:43:12 +0000100}
101
102CXString CXLoadedDiagnostic::getDiagnosticOption(CXString *Disable) const {
103 if (DiagOption.empty())
Dmitri Gribenkodc66adb2013-02-01 14:21:22 +0000104 return cxstring::createEmpty();
Ted Kremenek15322172011-11-10 08:43:12 +0000105
106 // FIXME: possibly refactor with logic in CXStoredDiagnostic.
107 if (Disable)
Dmitri Gribenko5595ded2013-02-02 02:19:29 +0000108 *Disable = cxstring::createDup((Twine("-Wno-") + DiagOption).str());
109 return cxstring::createDup((Twine("-W") + DiagOption).str());
Ted Kremenek15322172011-11-10 08:43:12 +0000110}
111
112unsigned CXLoadedDiagnostic::getCategory() const {
113 return category;
114}
115
Ted Kremenek78d5d3b2012-04-12 00:03:31 +0000116CXString CXLoadedDiagnostic::getCategoryText() const {
Dmitri Gribenko5595ded2013-02-02 02:19:29 +0000117 return cxstring::createDup(CategoryText);
Ted Kremenek78d5d3b2012-04-12 00:03:31 +0000118}
119
Ted Kremenek15322172011-11-10 08:43:12 +0000120unsigned CXLoadedDiagnostic::getNumRanges() const {
121 return Ranges.size();
122}
123
124CXSourceRange CXLoadedDiagnostic::getRange(unsigned Range) const {
125 assert(Range < Ranges.size());
126 return Ranges[Range];
127}
128
129unsigned CXLoadedDiagnostic::getNumFixIts() const {
130 return FixIts.size();
131}
132
133CXString CXLoadedDiagnostic::getFixIt(unsigned FixIt,
134 CXSourceRange *ReplacementRange) const {
135 assert(FixIt < FixIts.size());
136 if (ReplacementRange)
137 *ReplacementRange = FixIts[FixIt].first;
138 return FixIts[FixIt].second;
139}
140
141void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location,
142 CXFile *file,
143 unsigned int *line,
144 unsigned int *column,
145 unsigned int *offset) {
146
147
148 // CXSourceLocation consists of the following fields:
149 //
150 // void *ptr_data[2];
151 // unsigned int_data;
152 //
153 // The lowest bit of ptr_data[0] is always set to 1 to indicate this
154 // is a persistent diagnostic.
155 //
156 // For now, do the unoptimized approach and store the data in a side
157 // data structure. We can optimize this case later.
158
159 uintptr_t V = (uintptr_t) location.ptr_data[0];
160 assert((V & 0x1) == 1);
161 V &= ~(uintptr_t)1;
162
163 const Location &Loc = *((Location*)V);
164
165 if (file)
166 *file = Loc.file;
167 if (line)
168 *line = Loc.line;
169 if (column)
170 *column = Loc.column;
171 if (offset)
172 *offset = Loc.offset;
173}
174
175//===----------------------------------------------------------------------===//
176// Deserialize diagnostics.
177//===----------------------------------------------------------------------===//
178
179enum { MaxSupportedVersion = 1 };
180typedef SmallVector<uint64_t, 64> RecordData;
181enum LoadResult { Failure = 1, Success = 0 };
182enum StreamResult { Read_EndOfStream,
183 Read_BlockBegin,
184 Read_Failure,
185 Read_Record,
186 Read_BlockEnd };
187
188namespace {
189class DiagLoader {
190 enum CXLoadDiag_Error *error;
191 CXString *errorString;
192
193 void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
194 if (error)
195 *error = code;
196 if (errorString)
Dmitri Gribenko5595ded2013-02-02 02:19:29 +0000197 *errorString = cxstring::createDup(err);
Ted Kremenek15322172011-11-10 08:43:12 +0000198 }
199
200 void reportInvalidFile(llvm::StringRef err) {
201 return reportBad(CXLoadDiag_InvalidFile, err);
202 }
203
204 LoadResult readMetaBlock(llvm::BitstreamCursor &Stream);
205
206 LoadResult readDiagnosticBlock(llvm::BitstreamCursor &Stream,
207 CXDiagnosticSetImpl &Diags,
208 CXLoadedDiagnosticSetImpl &TopDiags);
209
210 StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
211 llvm::StringRef errorContext,
212 unsigned &BlockOrRecordID,
Chris Lattnere485f072013-01-19 21:35:35 +0000213 bool atTopLevel = false);
Ted Kremenek15322172011-11-10 08:43:12 +0000214
215
216 LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
217 Strings &strings, llvm::StringRef errorContext,
218 RecordData &Record,
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000219 StringRef Blob,
Ted Kremenek952538d2011-11-29 00:30:52 +0000220 bool allowEmptyString = false);
Ted Kremenek15322172011-11-10 08:43:12 +0000221
222 LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
223 llvm::StringRef &RetStr,
224 llvm::StringRef errorContext,
225 RecordData &Record,
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000226 StringRef Blob,
Ted Kremenek952538d2011-11-29 00:30:52 +0000227 bool allowEmptyString = false);
Ted Kremenek15322172011-11-10 08:43:12 +0000228
229 LoadResult readRange(CXLoadedDiagnosticSetImpl &TopDiags,
230 RecordData &Record, unsigned RecStartIdx,
231 CXSourceRange &SR);
232
233 LoadResult readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
234 RecordData &Record, unsigned &offset,
235 CXLoadedDiagnostic::Location &Loc);
236
237public:
238 DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
239 : error(e), errorString(es) {
240 if (error)
241 *error = CXLoadDiag_None;
242 if (errorString)
Dmitri Gribenkodc66adb2013-02-01 14:21:22 +0000243 *errorString = cxstring::createEmpty();
Ted Kremenek15322172011-11-10 08:43:12 +0000244 }
Ted Kremeneke97ac9e2011-11-11 15:19:48 +0000245
Ted Kremenek15322172011-11-10 08:43:12 +0000246 CXDiagnosticSet load(const char *file);
247};
248}
249
250CXDiagnosticSet DiagLoader::load(const char *file) {
251 // Open the diagnostics file.
252 std::string ErrStr;
253 FileSystemOptions FO;
254 FileManager FileMgr(FO);
255
Dylan Noblesmith1e4c01b2012-02-13 12:32:21 +0000256 OwningPtr<llvm::MemoryBuffer> Buffer;
Ted Kremenek15322172011-11-10 08:43:12 +0000257 Buffer.reset(FileMgr.getBufferForFile(file));
258
259 if (!Buffer) {
260 reportBad(CXLoadDiag_CannotLoad, ErrStr);
261 return 0;
262 }
263
264 llvm::BitstreamReader StreamFile;
265 StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
266 (const unsigned char *)Buffer->getBufferEnd());
267
268 llvm::BitstreamCursor Stream;
269 Stream.init(StreamFile);
270
271 // Sniff for the signature.
272 if (Stream.Read(8) != 'D' ||
273 Stream.Read(8) != 'I' ||
274 Stream.Read(8) != 'A' ||
275 Stream.Read(8) != 'G') {
276 reportBad(CXLoadDiag_InvalidFile,
277 "Bad header in diagnostics file");
278 return 0;
279 }
280
Chris Lattnere485f072013-01-19 21:35:35 +0000281 OwningPtr<CXLoadedDiagnosticSetImpl> Diags(new CXLoadedDiagnosticSetImpl());
Ted Kremenek15322172011-11-10 08:43:12 +0000282
283 while (true) {
284 unsigned BlockID = 0;
285 StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level",
286 BlockID, true);
287 switch (Res) {
288 case Read_EndOfStream:
289 return (CXDiagnosticSet) Diags.take();
290 case Read_Failure:
291 return 0;
292 case Read_Record:
293 llvm_unreachable("Top-level does not have records");
Ted Kremenek15322172011-11-10 08:43:12 +0000294 case Read_BlockEnd:
295 continue;
296 case Read_BlockBegin:
297 break;
298 }
299
300 switch (BlockID) {
301 case serialized_diags::BLOCK_META:
302 if (readMetaBlock(Stream))
303 return 0;
304 break;
305 case serialized_diags::BLOCK_DIAG:
306 if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get()))
307 return 0;
308 break;
309 default:
310 if (!Stream.SkipBlock()) {
311 reportInvalidFile("Malformed block at top-level of diagnostics file");
312 return 0;
313 }
314 break;
315 }
316 }
317}
318
319StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
320 llvm::StringRef errorContext,
321 unsigned &blockOrRecordID,
Chris Lattnere485f072013-01-19 21:35:35 +0000322 bool atTopLevel) {
Ted Kremenek15322172011-11-10 08:43:12 +0000323
324 blockOrRecordID = 0;
325
326 while (!Stream.AtEndOfStream()) {
327 unsigned Code = Stream.ReadCode();
328
329 // Handle the top-level specially.
330 if (atTopLevel) {
331 if (Code == llvm::bitc::ENTER_SUBBLOCK) {
332 unsigned BlockID = Stream.ReadSubBlockID();
333 if (BlockID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
334 if (Stream.ReadBlockInfoBlock()) {
335 reportInvalidFile("Malformed BlockInfoBlock in diagnostics file");
336 return Read_Failure;
337 }
338 continue;
339 }
340 blockOrRecordID = BlockID;
341 return Read_BlockBegin;
342 }
343 reportInvalidFile("Only blocks can appear at the top of a "
344 "diagnostic file");
345 return Read_Failure;
346 }
347
348 switch ((llvm::bitc::FixedAbbrevIDs)Code) {
349 case llvm::bitc::ENTER_SUBBLOCK:
350 blockOrRecordID = Stream.ReadSubBlockID();
351 return Read_BlockBegin;
352
353 case llvm::bitc::END_BLOCK:
354 if (Stream.ReadBlockEnd()) {
355 reportInvalidFile("Cannot read end of block");
356 return Read_Failure;
357 }
358 return Read_BlockEnd;
359
360 case llvm::bitc::DEFINE_ABBREV:
361 Stream.ReadAbbrevRecord();
362 continue;
363
364 case llvm::bitc::UNABBREV_RECORD:
365 reportInvalidFile("Diagnostics file should have no unabbreviated "
366 "records");
367 return Read_Failure;
368
369 default:
370 // We found a record.
371 blockOrRecordID = Code;
372 return Read_Record;
373 }
374 }
375
376 if (atTopLevel)
377 return Read_EndOfStream;
378
379 reportInvalidFile(Twine("Premature end of diagnostics file within ").str() +
380 errorContext.str());
381 return Read_Failure;
382}
383
384LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
385 if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
386 reportInvalidFile("Malformed metadata block");
387 return Failure;
388 }
389
390 bool versionChecked = false;
391
392 while (true) {
393 unsigned blockOrCode = 0;
394 StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block",
395 blockOrCode);
396
397 switch(Res) {
398 case Read_EndOfStream:
399 llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock");
400 case Read_Failure:
401 return Failure;
402 case Read_Record:
403 break;
404 case Read_BlockBegin:
405 if (Stream.SkipBlock()) {
406 reportInvalidFile("Malformed metadata block");
407 return Failure;
408 }
409 case Read_BlockEnd:
410 if (!versionChecked) {
411 reportInvalidFile("Diagnostics file does not contain version"
412 " information");
413 return Failure;
414 }
415 return Success;
416 }
417
418 RecordData Record;
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000419 unsigned recordID = Stream.readRecord(blockOrCode, Record);
Ted Kremenek15322172011-11-10 08:43:12 +0000420
421 if (recordID == serialized_diags::RECORD_VERSION) {
422 if (Record.size() < 1) {
423 reportInvalidFile("malformed VERSION identifier in diagnostics file");
424 return Failure;
425 }
426 if (Record[0] > MaxSupportedVersion) {
427 reportInvalidFile("diagnosics file is a newer version than the one "
428 "supported");
429 return Failure;
430 }
431 versionChecked = true;
432 }
433 }
434}
435
436LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
437 llvm::StringRef &RetStr,
438 llvm::StringRef errorContext,
439 RecordData &Record,
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000440 StringRef Blob,
Ted Kremenek952538d2011-11-29 00:30:52 +0000441 bool allowEmptyString) {
Ted Kremenek15322172011-11-10 08:43:12 +0000442
443 // Basic buffer overflow check.
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000444 if (Blob.size() > 65536) {
Ted Kremenek15322172011-11-10 08:43:12 +0000445 reportInvalidFile(std::string("Out-of-bounds string in ") +
446 std::string(errorContext));
447 return Failure;
448 }
Ted Kremenek952538d2011-11-29 00:30:52 +0000449
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000450 if (allowEmptyString && Record.size() >= 1 && Blob.size() == 0) {
Ted Kremenek952538d2011-11-29 00:30:52 +0000451 RetStr = "";
452 return Success;
453 }
Ted Kremenek15322172011-11-10 08:43:12 +0000454
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000455 if (Record.size() < 1 || Blob.size() == 0) {
Ted Kremenek15322172011-11-10 08:43:12 +0000456 reportInvalidFile(std::string("Corrupted ") + std::string(errorContext)
457 + std::string(" entry"));
458 return Failure;
459 }
460
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000461 RetStr = TopDiags.makeString(Blob);
Ted Kremenek15322172011-11-10 08:43:12 +0000462 return Success;
463}
464
465LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
466 Strings &strings,
467 llvm::StringRef errorContext,
468 RecordData &Record,
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000469 StringRef Blob,
Ted Kremenek952538d2011-11-29 00:30:52 +0000470 bool allowEmptyString) {
Ted Kremenek15322172011-11-10 08:43:12 +0000471 llvm::StringRef RetStr;
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000472 if (readString(TopDiags, RetStr, errorContext, Record, Blob,
Ted Kremenek952538d2011-11-29 00:30:52 +0000473 allowEmptyString))
Ted Kremenek15322172011-11-10 08:43:12 +0000474 return Failure;
475 strings[Record[0]] = RetStr;
476 return Success;
477}
478
479LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
480 RecordData &Record, unsigned &offset,
481 CXLoadedDiagnostic::Location &Loc) {
482 if (Record.size() < offset + 3) {
483 reportInvalidFile("Corrupted source location");
484 return Failure;
485 }
486
487 unsigned fileID = Record[offset++];
488 if (fileID == 0) {
489 // Sentinel value.
490 Loc.file = 0;
491 Loc.line = 0;
492 Loc.column = 0;
493 Loc.offset = 0;
494 return Success;
495 }
496
497 const FileEntry *FE = TopDiags.Files[fileID];
498 if (!FE) {
499 reportInvalidFile("Corrupted file entry in source location");
500 return Failure;
501 }
David Greene527ce9f2013-01-15 22:09:48 +0000502 Loc.file = const_cast<FileEntry *>(FE);
Ted Kremenek15322172011-11-10 08:43:12 +0000503 Loc.line = Record[offset++];
504 Loc.column = Record[offset++];
505 Loc.offset = Record[offset++];
506 return Success;
507}
508
509LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags,
510 RecordData &Record,
511 unsigned int RecStartIdx,
512 CXSourceRange &SR) {
513 CXLoadedDiagnostic::Location *Start, *End;
514 Start = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
515 End = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
516
517 if (readLocation(TopDiags, Record, RecStartIdx, *Start))
518 return Failure;
519 if (readLocation(TopDiags, Record, RecStartIdx, *End))
520 return Failure;
521
522 CXSourceLocation startLoc = makeLocation(Start);
523 CXSourceLocation endLoc = makeLocation(End);
524 SR = clang_getRange(startLoc, endLoc);
525 return Success;
526}
527
528LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
529 CXDiagnosticSetImpl &Diags,
530 CXLoadedDiagnosticSetImpl &TopDiags){
531
532 if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
533 reportInvalidFile("malformed diagnostic block");
534 return Failure;
535 }
536
Dylan Noblesmith1e4c01b2012-02-13 12:32:21 +0000537 OwningPtr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic());
Ted Kremenek15322172011-11-10 08:43:12 +0000538 RecordData Record;
539
540 while (true) {
541 unsigned blockOrCode = 0;
542 StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block",
543 blockOrCode);
544 switch (Res) {
545 case Read_EndOfStream:
546 llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock");
Ted Kremenek15322172011-11-10 08:43:12 +0000547 case Read_Failure:
548 return Failure;
549 case Read_BlockBegin: {
550 // The only blocks we care about are subdiagnostics.
551 if (blockOrCode != serialized_diags::BLOCK_DIAG) {
552 if (!Stream.SkipBlock()) {
553 reportInvalidFile("Invalid subblock in Diagnostics block");
554 return Failure;
555 }
556 } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(),
557 TopDiags)) {
558 return Failure;
559 }
560
561 continue;
562 }
563 case Read_BlockEnd:
564 Diags.appendDiagnostic(D.take());
565 return Success;
566 case Read_Record:
567 break;
568 }
569
570 // Read the record.
571 Record.clear();
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000572 StringRef Blob;
573 unsigned recID = Stream.readRecord(blockOrCode, Record, &Blob);
Ted Kremenek15322172011-11-10 08:43:12 +0000574
575 if (recID < serialized_diags::RECORD_FIRST ||
576 recID > serialized_diags::RECORD_LAST)
577 continue;
578
579 switch ((serialized_diags::RecordIDs)recID) {
580 case serialized_diags::RECORD_VERSION:
581 continue;
582 case serialized_diags::RECORD_CATEGORY:
583 if (readString(TopDiags, TopDiags.Categories, "category", Record,
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000584 Blob, /* allowEmptyString */ true))
Ted Kremenek15322172011-11-10 08:43:12 +0000585 return Failure;
586 continue;
587
588 case serialized_diags::RECORD_DIAG_FLAG:
589 if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record,
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000590 Blob))
Ted Kremenek15322172011-11-10 08:43:12 +0000591 return Failure;
592 continue;
593
594 case serialized_diags::RECORD_FILENAME: {
595 if (readString(TopDiags, TopDiags.FileNames, "filename", Record,
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000596 Blob))
Ted Kremenek15322172011-11-10 08:43:12 +0000597 return Failure;
598
599 if (Record.size() < 3) {
600 reportInvalidFile("Invalid file entry");
601 return Failure;
602 }
603
604 const FileEntry *FE =
605 TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]],
606 /* size */ Record[1],
607 /* time */ Record[2]);
608
609 TopDiags.Files[Record[0]] = FE;
610 continue;
611 }
612
613 case serialized_diags::RECORD_SOURCE_RANGE: {
614 CXSourceRange SR;
615 if (readRange(TopDiags, Record, 0, SR))
616 return Failure;
617 D->Ranges.push_back(SR);
618 continue;
619 }
620
621 case serialized_diags::RECORD_FIXIT: {
622 CXSourceRange SR;
623 if (readRange(TopDiags, Record, 0, SR))
624 return Failure;
625 llvm::StringRef RetStr;
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000626 if (readString(TopDiags, RetStr, "FIXIT", Record, Blob,
Ted Kremenek952538d2011-11-29 00:30:52 +0000627 /* allowEmptyString */ true))
Ted Kremenek15322172011-11-10 08:43:12 +0000628 return Failure;
Dmitri Gribenko5595ded2013-02-02 02:19:29 +0000629 D->FixIts.push_back(std::make_pair(SR, cxstring::createRef(RetStr)));
Ted Kremeneke97ac9e2011-11-11 15:19:48 +0000630 continue;
Ted Kremenek15322172011-11-10 08:43:12 +0000631 }
632
633 case serialized_diags::RECORD_DIAG: {
634 D->severity = Record[0];
635 unsigned offset = 1;
636 if (readLocation(TopDiags, Record, offset, D->DiagLoc))
637 return Failure;
638 D->category = Record[offset++];
639 unsigned diagFlag = Record[offset++];
640 D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : "";
Ted Kremenek78d5d3b2012-04-12 00:03:31 +0000641 D->CategoryText = D->category ? TopDiags.Categories[D->category] : "";
Chris Lattnerb3ce3572013-01-20 02:38:54 +0000642 D->Spelling = TopDiags.makeString(Blob);
Ted Kremenek15322172011-11-10 08:43:12 +0000643 continue;
644 }
645 }
646 }
647}
648
649extern "C" {
650CXDiagnosticSet clang_loadDiagnostics(const char *file,
651 enum CXLoadDiag_Error *error,
652 CXString *errorString) {
653 DiagLoader L(error, errorString);
654 return L.load(file);
655}
656} // end extern 'C'.