blob: f81922416dd0540ef065e9c712bcd1e8deebca75 [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;
27using namespace clang::cxstring;
28
29//===----------------------------------------------------------------------===//
30// Extend CXDiagnosticSetImpl which contains strings for diagnostics.
31//===----------------------------------------------------------------------===//
32
33typedef llvm::DenseMap<unsigned, llvm::StringRef> Strings;
34
35namespace {
36class CXLoadedDiagnosticSetImpl : public CXDiagnosticSetImpl {
37public:
38 CXLoadedDiagnosticSetImpl() : CXDiagnosticSetImpl(true), FakeFiles(FO) {}
39 virtual ~CXLoadedDiagnosticSetImpl() {}
40
41 llvm::StringRef makeString(const char *blob, unsigned blobLen);
42
43 llvm::BumpPtrAllocator Alloc;
44 Strings Categories;
45 Strings WarningFlags;
46 Strings FileNames;
47
48 FileSystemOptions FO;
49 FileManager FakeFiles;
50 llvm::DenseMap<unsigned, const FileEntry *> Files;
51};
52}
53
54llvm::StringRef CXLoadedDiagnosticSetImpl::makeString(const char *blob,
55 unsigned bloblen) {
Ted Kremeneke97ac9e2011-11-11 15:19:48 +000056 char *mem = Alloc.Allocate<char>(bloblen + 1);
Ted Kremenek15322172011-11-10 08:43:12 +000057 memcpy(mem, blob, bloblen);
Ted Kremeneke97ac9e2011-11-11 15:19:48 +000058 // Add a null terminator for those clients accessing the buffer
59 // like a c-string.
60 mem[bloblen] = '\0';
Ted Kremenek15322172011-11-10 08:43:12 +000061 return llvm::StringRef(mem, bloblen);
62}
63
64//===----------------------------------------------------------------------===//
65// Cleanup.
66//===----------------------------------------------------------------------===//
67
68CXLoadedDiagnostic::~CXLoadedDiagnostic() {}
69
70//===----------------------------------------------------------------------===//
71// Public CXLoadedDiagnostic methods.
72//===----------------------------------------------------------------------===//
73
74CXDiagnosticSeverity CXLoadedDiagnostic::getSeverity() const {
75 // FIXME: possibly refactor with logic in CXStoredDiagnostic.
76 switch (severity) {
77 case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored;
78 case DiagnosticsEngine::Note: return CXDiagnostic_Note;
79 case DiagnosticsEngine::Warning: return CXDiagnostic_Warning;
80 case DiagnosticsEngine::Error: return CXDiagnostic_Error;
81 case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal;
82 }
83
84 llvm_unreachable("Invalid diagnostic level");
Ted Kremenek15322172011-11-10 08:43:12 +000085}
86
87static CXSourceLocation makeLocation(const CXLoadedDiagnostic::Location *DLoc) {
88 // The lowest bit of ptr_data[0] is always set to 1 to indicate this
89 // is a persistent diagnostic.
90 uintptr_t V = (uintptr_t) DLoc;
91 V |= 0x1;
92 CXSourceLocation Loc = { { (void*) V, 0 }, 0 };
93 return Loc;
94}
95
96CXSourceLocation CXLoadedDiagnostic::getLocation() const {
97 // The lowest bit of ptr_data[0] is always set to 1 to indicate this
98 // is a persistent diagnostic.
99 return makeLocation(&DiagLoc);
100}
101
102CXString CXLoadedDiagnostic::getSpelling() const {
Ted Kremeneke97ac9e2011-11-11 15:19:48 +0000103 return cxstring::createCXString(Spelling, false);
Ted Kremenek15322172011-11-10 08:43:12 +0000104}
105
106CXString CXLoadedDiagnostic::getDiagnosticOption(CXString *Disable) const {
107 if (DiagOption.empty())
108 return createCXString("");
109
110 // FIXME: possibly refactor with logic in CXStoredDiagnostic.
111 if (Disable)
112 *Disable = createCXString((Twine("-Wno-") + DiagOption).str());
113 return createCXString((Twine("-W") + DiagOption).str());
114}
115
116unsigned CXLoadedDiagnostic::getCategory() const {
117 return category;
118}
119
Ted Kremenek78d5d3b2012-04-12 00:03:31 +0000120CXString CXLoadedDiagnostic::getCategoryText() const {
121 return cxstring::createCXString(CategoryText);
122}
123
Ted Kremenek15322172011-11-10 08:43:12 +0000124unsigned CXLoadedDiagnostic::getNumRanges() const {
125 return Ranges.size();
126}
127
128CXSourceRange CXLoadedDiagnostic::getRange(unsigned Range) const {
129 assert(Range < Ranges.size());
130 return Ranges[Range];
131}
132
133unsigned CXLoadedDiagnostic::getNumFixIts() const {
134 return FixIts.size();
135}
136
137CXString CXLoadedDiagnostic::getFixIt(unsigned FixIt,
138 CXSourceRange *ReplacementRange) const {
139 assert(FixIt < FixIts.size());
140 if (ReplacementRange)
141 *ReplacementRange = FixIts[FixIt].first;
142 return FixIts[FixIt].second;
143}
144
145void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location,
146 CXFile *file,
147 unsigned int *line,
148 unsigned int *column,
149 unsigned int *offset) {
150
151
152 // CXSourceLocation consists of the following fields:
153 //
154 // void *ptr_data[2];
155 // unsigned int_data;
156 //
157 // The lowest bit of ptr_data[0] is always set to 1 to indicate this
158 // is a persistent diagnostic.
159 //
160 // For now, do the unoptimized approach and store the data in a side
161 // data structure. We can optimize this case later.
162
163 uintptr_t V = (uintptr_t) location.ptr_data[0];
164 assert((V & 0x1) == 1);
165 V &= ~(uintptr_t)1;
166
167 const Location &Loc = *((Location*)V);
168
169 if (file)
170 *file = Loc.file;
171 if (line)
172 *line = Loc.line;
173 if (column)
174 *column = Loc.column;
175 if (offset)
176 *offset = Loc.offset;
177}
178
179//===----------------------------------------------------------------------===//
180// Deserialize diagnostics.
181//===----------------------------------------------------------------------===//
182
183enum { MaxSupportedVersion = 1 };
184typedef SmallVector<uint64_t, 64> RecordData;
185enum LoadResult { Failure = 1, Success = 0 };
186enum StreamResult { Read_EndOfStream,
187 Read_BlockBegin,
188 Read_Failure,
189 Read_Record,
190 Read_BlockEnd };
191
192namespace {
193class DiagLoader {
194 enum CXLoadDiag_Error *error;
195 CXString *errorString;
196
197 void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
198 if (error)
199 *error = code;
200 if (errorString)
201 *errorString = createCXString(err);
202 }
203
204 void reportInvalidFile(llvm::StringRef err) {
205 return reportBad(CXLoadDiag_InvalidFile, err);
206 }
207
208 LoadResult readMetaBlock(llvm::BitstreamCursor &Stream);
209
210 LoadResult readDiagnosticBlock(llvm::BitstreamCursor &Stream,
211 CXDiagnosticSetImpl &Diags,
212 CXLoadedDiagnosticSetImpl &TopDiags);
213
214 StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
215 llvm::StringRef errorContext,
216 unsigned &BlockOrRecordID,
Chris Lattnere485f072013-01-19 21:35:35 +0000217 bool atTopLevel = false);
Ted Kremenek15322172011-11-10 08:43:12 +0000218
219
220 LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
221 Strings &strings, llvm::StringRef errorContext,
222 RecordData &Record,
223 const char *BlobStart,
Ted Kremenek952538d2011-11-29 00:30:52 +0000224 unsigned BlobLen,
225 bool allowEmptyString = false);
Ted Kremenek15322172011-11-10 08:43:12 +0000226
227 LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
228 llvm::StringRef &RetStr,
229 llvm::StringRef errorContext,
230 RecordData &Record,
231 const char *BlobStart,
Ted Kremenek952538d2011-11-29 00:30:52 +0000232 unsigned BlobLen,
233 bool allowEmptyString = false);
Ted Kremenek15322172011-11-10 08:43:12 +0000234
235 LoadResult readRange(CXLoadedDiagnosticSetImpl &TopDiags,
236 RecordData &Record, unsigned RecStartIdx,
237 CXSourceRange &SR);
238
239 LoadResult readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
240 RecordData &Record, unsigned &offset,
241 CXLoadedDiagnostic::Location &Loc);
242
243public:
244 DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
245 : error(e), errorString(es) {
246 if (error)
247 *error = CXLoadDiag_None;
248 if (errorString)
249 *errorString = createCXString("");
250 }
Ted Kremeneke97ac9e2011-11-11 15:19:48 +0000251
Ted Kremenek15322172011-11-10 08:43:12 +0000252 CXDiagnosticSet load(const char *file);
253};
254}
255
256CXDiagnosticSet DiagLoader::load(const char *file) {
257 // Open the diagnostics file.
258 std::string ErrStr;
259 FileSystemOptions FO;
260 FileManager FileMgr(FO);
261
Dylan Noblesmith1e4c01b2012-02-13 12:32:21 +0000262 OwningPtr<llvm::MemoryBuffer> Buffer;
Ted Kremenek15322172011-11-10 08:43:12 +0000263 Buffer.reset(FileMgr.getBufferForFile(file));
264
265 if (!Buffer) {
266 reportBad(CXLoadDiag_CannotLoad, ErrStr);
267 return 0;
268 }
269
270 llvm::BitstreamReader StreamFile;
271 StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
272 (const unsigned char *)Buffer->getBufferEnd());
273
274 llvm::BitstreamCursor Stream;
275 Stream.init(StreamFile);
276
277 // Sniff for the signature.
278 if (Stream.Read(8) != 'D' ||
279 Stream.Read(8) != 'I' ||
280 Stream.Read(8) != 'A' ||
281 Stream.Read(8) != 'G') {
282 reportBad(CXLoadDiag_InvalidFile,
283 "Bad header in diagnostics file");
284 return 0;
285 }
286
Chris Lattnere485f072013-01-19 21:35:35 +0000287 OwningPtr<CXLoadedDiagnosticSetImpl> Diags(new CXLoadedDiagnosticSetImpl());
Ted Kremenek15322172011-11-10 08:43:12 +0000288
289 while (true) {
290 unsigned BlockID = 0;
291 StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level",
292 BlockID, true);
293 switch (Res) {
294 case Read_EndOfStream:
295 return (CXDiagnosticSet) Diags.take();
296 case Read_Failure:
297 return 0;
298 case Read_Record:
299 llvm_unreachable("Top-level does not have records");
Ted Kremenek15322172011-11-10 08:43:12 +0000300 case Read_BlockEnd:
301 continue;
302 case Read_BlockBegin:
303 break;
304 }
305
306 switch (BlockID) {
307 case serialized_diags::BLOCK_META:
308 if (readMetaBlock(Stream))
309 return 0;
310 break;
311 case serialized_diags::BLOCK_DIAG:
312 if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get()))
313 return 0;
314 break;
315 default:
316 if (!Stream.SkipBlock()) {
317 reportInvalidFile("Malformed block at top-level of diagnostics file");
318 return 0;
319 }
320 break;
321 }
322 }
323}
324
325StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
326 llvm::StringRef errorContext,
327 unsigned &blockOrRecordID,
Chris Lattnere485f072013-01-19 21:35:35 +0000328 bool atTopLevel) {
Ted Kremenek15322172011-11-10 08:43:12 +0000329
330 blockOrRecordID = 0;
331
332 while (!Stream.AtEndOfStream()) {
333 unsigned Code = Stream.ReadCode();
334
335 // Handle the top-level specially.
336 if (atTopLevel) {
337 if (Code == llvm::bitc::ENTER_SUBBLOCK) {
338 unsigned BlockID = Stream.ReadSubBlockID();
339 if (BlockID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
340 if (Stream.ReadBlockInfoBlock()) {
341 reportInvalidFile("Malformed BlockInfoBlock in diagnostics file");
342 return Read_Failure;
343 }
344 continue;
345 }
346 blockOrRecordID = BlockID;
347 return Read_BlockBegin;
348 }
349 reportInvalidFile("Only blocks can appear at the top of a "
350 "diagnostic file");
351 return Read_Failure;
352 }
353
354 switch ((llvm::bitc::FixedAbbrevIDs)Code) {
355 case llvm::bitc::ENTER_SUBBLOCK:
356 blockOrRecordID = Stream.ReadSubBlockID();
357 return Read_BlockBegin;
358
359 case llvm::bitc::END_BLOCK:
360 if (Stream.ReadBlockEnd()) {
361 reportInvalidFile("Cannot read end of block");
362 return Read_Failure;
363 }
364 return Read_BlockEnd;
365
366 case llvm::bitc::DEFINE_ABBREV:
367 Stream.ReadAbbrevRecord();
368 continue;
369
370 case llvm::bitc::UNABBREV_RECORD:
371 reportInvalidFile("Diagnostics file should have no unabbreviated "
372 "records");
373 return Read_Failure;
374
375 default:
376 // We found a record.
377 blockOrRecordID = Code;
378 return Read_Record;
379 }
380 }
381
382 if (atTopLevel)
383 return Read_EndOfStream;
384
385 reportInvalidFile(Twine("Premature end of diagnostics file within ").str() +
386 errorContext.str());
387 return Read_Failure;
388}
389
390LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
391 if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
392 reportInvalidFile("Malformed metadata block");
393 return Failure;
394 }
395
396 bool versionChecked = false;
397
398 while (true) {
399 unsigned blockOrCode = 0;
400 StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block",
401 blockOrCode);
402
403 switch(Res) {
404 case Read_EndOfStream:
405 llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock");
406 case Read_Failure:
407 return Failure;
408 case Read_Record:
409 break;
410 case Read_BlockBegin:
411 if (Stream.SkipBlock()) {
412 reportInvalidFile("Malformed metadata block");
413 return Failure;
414 }
415 case Read_BlockEnd:
416 if (!versionChecked) {
417 reportInvalidFile("Diagnostics file does not contain version"
418 " information");
419 return Failure;
420 }
421 return Success;
422 }
423
424 RecordData Record;
425 const char *Blob;
426 unsigned BlobLen;
427 unsigned recordID = Stream.ReadRecord(blockOrCode, Record, &Blob, &BlobLen);
428
429 if (recordID == serialized_diags::RECORD_VERSION) {
430 if (Record.size() < 1) {
431 reportInvalidFile("malformed VERSION identifier in diagnostics file");
432 return Failure;
433 }
434 if (Record[0] > MaxSupportedVersion) {
435 reportInvalidFile("diagnosics file is a newer version than the one "
436 "supported");
437 return Failure;
438 }
439 versionChecked = true;
440 }
441 }
442}
443
444LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
445 llvm::StringRef &RetStr,
446 llvm::StringRef errorContext,
447 RecordData &Record,
448 const char *BlobStart,
Ted Kremenek952538d2011-11-29 00:30:52 +0000449 unsigned BlobLen,
450 bool allowEmptyString) {
Ted Kremenek15322172011-11-10 08:43:12 +0000451
452 // Basic buffer overflow check.
453 if (BlobLen > 65536) {
454 reportInvalidFile(std::string("Out-of-bounds string in ") +
455 std::string(errorContext));
456 return Failure;
457 }
Ted Kremenek952538d2011-11-29 00:30:52 +0000458
459 if (allowEmptyString && Record.size() >= 1 && BlobLen == 0) {
460 RetStr = "";
461 return Success;
462 }
Ted Kremenek15322172011-11-10 08:43:12 +0000463
464 if (Record.size() < 1 || BlobLen == 0) {
465 reportInvalidFile(std::string("Corrupted ") + std::string(errorContext)
466 + std::string(" entry"));
467 return Failure;
468 }
469
470 RetStr = TopDiags.makeString(BlobStart, BlobLen);
471 return Success;
472}
473
474LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
475 Strings &strings,
476 llvm::StringRef errorContext,
477 RecordData &Record,
478 const char *BlobStart,
Ted Kremenek952538d2011-11-29 00:30:52 +0000479 unsigned BlobLen,
480 bool allowEmptyString) {
Ted Kremenek15322172011-11-10 08:43:12 +0000481 llvm::StringRef RetStr;
Ted Kremenek952538d2011-11-29 00:30:52 +0000482 if (readString(TopDiags, RetStr, errorContext, Record, BlobStart, BlobLen,
483 allowEmptyString))
Ted Kremenek15322172011-11-10 08:43:12 +0000484 return Failure;
485 strings[Record[0]] = RetStr;
486 return Success;
487}
488
489LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
490 RecordData &Record, unsigned &offset,
491 CXLoadedDiagnostic::Location &Loc) {
492 if (Record.size() < offset + 3) {
493 reportInvalidFile("Corrupted source location");
494 return Failure;
495 }
496
497 unsigned fileID = Record[offset++];
498 if (fileID == 0) {
499 // Sentinel value.
500 Loc.file = 0;
501 Loc.line = 0;
502 Loc.column = 0;
503 Loc.offset = 0;
504 return Success;
505 }
506
507 const FileEntry *FE = TopDiags.Files[fileID];
508 if (!FE) {
509 reportInvalidFile("Corrupted file entry in source location");
510 return Failure;
511 }
David Greene527ce9f2013-01-15 22:09:48 +0000512 Loc.file = const_cast<FileEntry *>(FE);
Ted Kremenek15322172011-11-10 08:43:12 +0000513 Loc.line = Record[offset++];
514 Loc.column = Record[offset++];
515 Loc.offset = Record[offset++];
516 return Success;
517}
518
519LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags,
520 RecordData &Record,
521 unsigned int RecStartIdx,
522 CXSourceRange &SR) {
523 CXLoadedDiagnostic::Location *Start, *End;
524 Start = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
525 End = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
526
527 if (readLocation(TopDiags, Record, RecStartIdx, *Start))
528 return Failure;
529 if (readLocation(TopDiags, Record, RecStartIdx, *End))
530 return Failure;
531
532 CXSourceLocation startLoc = makeLocation(Start);
533 CXSourceLocation endLoc = makeLocation(End);
534 SR = clang_getRange(startLoc, endLoc);
535 return Success;
536}
537
538LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
539 CXDiagnosticSetImpl &Diags,
540 CXLoadedDiagnosticSetImpl &TopDiags){
541
542 if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
543 reportInvalidFile("malformed diagnostic block");
544 return Failure;
545 }
546
Dylan Noblesmith1e4c01b2012-02-13 12:32:21 +0000547 OwningPtr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic());
Ted Kremenek15322172011-11-10 08:43:12 +0000548 RecordData Record;
549
550 while (true) {
551 unsigned blockOrCode = 0;
552 StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block",
553 blockOrCode);
554 switch (Res) {
555 case Read_EndOfStream:
556 llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock");
Ted Kremenek15322172011-11-10 08:43:12 +0000557 case Read_Failure:
558 return Failure;
559 case Read_BlockBegin: {
560 // The only blocks we care about are subdiagnostics.
561 if (blockOrCode != serialized_diags::BLOCK_DIAG) {
562 if (!Stream.SkipBlock()) {
563 reportInvalidFile("Invalid subblock in Diagnostics block");
564 return Failure;
565 }
566 } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(),
567 TopDiags)) {
568 return Failure;
569 }
570
571 continue;
572 }
573 case Read_BlockEnd:
574 Diags.appendDiagnostic(D.take());
575 return Success;
576 case Read_Record:
577 break;
578 }
579
580 // Read the record.
581 Record.clear();
582 const char *BlobStart = 0;
583 unsigned BlobLen = 0;
584 unsigned recID = Stream.ReadRecord(blockOrCode, Record,
585 BlobStart, BlobLen);
586
587 if (recID < serialized_diags::RECORD_FIRST ||
588 recID > serialized_diags::RECORD_LAST)
589 continue;
590
591 switch ((serialized_diags::RecordIDs)recID) {
592 case serialized_diags::RECORD_VERSION:
593 continue;
594 case serialized_diags::RECORD_CATEGORY:
595 if (readString(TopDiags, TopDiags.Categories, "category", Record,
Ted Kremenek13eee192011-12-07 02:08:00 +0000596 BlobStart, BlobLen,
597 /* allowEmptyString */ true))
Ted Kremenek15322172011-11-10 08:43:12 +0000598 return Failure;
599 continue;
600
601 case serialized_diags::RECORD_DIAG_FLAG:
602 if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record,
603 BlobStart, BlobLen))
604 return Failure;
605 continue;
606
607 case serialized_diags::RECORD_FILENAME: {
608 if (readString(TopDiags, TopDiags.FileNames, "filename", Record,
609 BlobStart, BlobLen))
610 return Failure;
611
612 if (Record.size() < 3) {
613 reportInvalidFile("Invalid file entry");
614 return Failure;
615 }
616
617 const FileEntry *FE =
618 TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]],
619 /* size */ Record[1],
620 /* time */ Record[2]);
621
622 TopDiags.Files[Record[0]] = FE;
623 continue;
624 }
625
626 case serialized_diags::RECORD_SOURCE_RANGE: {
627 CXSourceRange SR;
628 if (readRange(TopDiags, Record, 0, SR))
629 return Failure;
630 D->Ranges.push_back(SR);
631 continue;
632 }
633
634 case serialized_diags::RECORD_FIXIT: {
635 CXSourceRange SR;
636 if (readRange(TopDiags, Record, 0, SR))
637 return Failure;
638 llvm::StringRef RetStr;
Ted Kremenek952538d2011-11-29 00:30:52 +0000639 if (readString(TopDiags, RetStr, "FIXIT", Record, BlobStart, BlobLen,
640 /* allowEmptyString */ true))
Ted Kremenek15322172011-11-10 08:43:12 +0000641 return Failure;
Ted Kremeneke97ac9e2011-11-11 15:19:48 +0000642 D->FixIts.push_back(std::make_pair(SR, createCXString(RetStr, false)));
643 continue;
Ted Kremenek15322172011-11-10 08:43:12 +0000644 }
645
646 case serialized_diags::RECORD_DIAG: {
647 D->severity = Record[0];
648 unsigned offset = 1;
649 if (readLocation(TopDiags, Record, offset, D->DiagLoc))
650 return Failure;
651 D->category = Record[offset++];
652 unsigned diagFlag = Record[offset++];
653 D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : "";
Ted Kremenek78d5d3b2012-04-12 00:03:31 +0000654 D->CategoryText = D->category ? TopDiags.Categories[D->category] : "";
Ted Kremenek15322172011-11-10 08:43:12 +0000655 D->Spelling = TopDiags.makeString(BlobStart, BlobLen);
656 continue;
657 }
658 }
659 }
660}
661
662extern "C" {
663CXDiagnosticSet clang_loadDiagnostics(const char *file,
664 enum CXLoadDiag_Error *error,
665 CXString *errorString) {
666 DiagLoader L(error, errorString);
667 return L.load(file);
668}
669} // end extern 'C'.