blob: 2871256b0cbace2be46eb72847176b10eca3855c [file] [log] [blame]
Chris Lattner5b25f0b2013-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 Kremenekd010ba42011-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"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000018#include "clang/Basic/LLVM.h"
Ted Kremenekd010ba42011-11-10 08:43:12 +000019#include "clang/Frontend/SerializedDiagnosticPrinter.h"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000020#include "llvm/ADT/Optional.h"
Ted Kremenekd010ba42011-11-10 08:43:12 +000021#include "llvm/ADT/StringRef.h"
22#include "llvm/ADT/Twine.h"
Ted Kremenekd010ba42011-11-10 08:43:12 +000023#include "llvm/Bitcode/BitstreamReader.h"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000024#include "llvm/Support/ErrorHandling.h"
Ted Kremenekd010ba42011-11-10 08:43:12 +000025#include "llvm/Support/MemoryBuffer.h"
Ted Kremenekd010ba42011-11-10 08:43:12 +000026using namespace clang;
Ted Kremenekd010ba42011-11-10 08:43:12 +000027
28//===----------------------------------------------------------------------===//
29// Extend CXDiagnosticSetImpl which contains strings for diagnostics.
30//===----------------------------------------------------------------------===//
31
Dmitri Gribenko7d098082013-02-18 19:50:38 +000032typedef llvm::DenseMap<unsigned, const char *> Strings;
Ted Kremenekd010ba42011-11-10 08:43:12 +000033
34namespace {
35class CXLoadedDiagnosticSetImpl : public CXDiagnosticSetImpl {
36public:
37 CXLoadedDiagnosticSetImpl() : CXDiagnosticSetImpl(true), FakeFiles(FO) {}
38 virtual ~CXLoadedDiagnosticSetImpl() {}
39
Ted Kremenekd010ba42011-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;
Dmitri Gribenko7d098082013-02-18 19:50:38 +000048
49 /// \brief Copy the string into our own allocator.
50 const char *copyString(StringRef Blob) {
Chris Lattner0e6c9402013-01-20 02:38:54 +000051 char *mem = Alloc.Allocate<char>(Blob.size() + 1);
52 memcpy(mem, Blob.data(), Blob.size());
Chris Lattner0e6c9402013-01-20 02:38:54 +000053 mem[Blob.size()] = '\0';
Dmitri Gribenko7d098082013-02-18 19:50:38 +000054 return mem;
Chris Lattner0e6c9402013-01-20 02:38:54 +000055 }
Ted Kremenekd010ba42011-11-10 08:43:12 +000056};
57}
58
Ted Kremenekd010ba42011-11-10 08:43:12 +000059//===----------------------------------------------------------------------===//
60// Cleanup.
61//===----------------------------------------------------------------------===//
62
63CXLoadedDiagnostic::~CXLoadedDiagnostic() {}
64
65//===----------------------------------------------------------------------===//
66// Public CXLoadedDiagnostic methods.
67//===----------------------------------------------------------------------===//
68
69CXDiagnosticSeverity CXLoadedDiagnostic::getSeverity() const {
Jordan Rose7ef1c382014-03-03 18:29:52 +000070 // FIXME: Fail more softly if the diagnostic level is unknown?
Jordan Roseaf710312014-03-04 17:45:43 +000071 auto severityAsLevel = static_cast<serialized_diags::Level>(severity);
72 assert(severity == static_cast<unsigned>(severityAsLevel) &&
Jordan Rose7ef1c382014-03-03 18:29:52 +000073 "unknown serialized diagnostic level");
74
Jordan Roseaf710312014-03-04 17:45:43 +000075 switch (severityAsLevel) {
Jordan Rose7ef1c382014-03-03 18:29:52 +000076#define CASE(X) case serialized_diags::X: return CXDiagnostic_##X;
77 CASE(Ignored)
78 CASE(Note)
79 CASE(Warning)
80 CASE(Error)
81 CASE(Fatal)
82 CASE(Remark)
83#undef CASE
Ted Kremenekd010ba42011-11-10 08:43:12 +000084 }
85
86 llvm_unreachable("Invalid diagnostic level");
Ted Kremenekd010ba42011-11-10 08:43:12 +000087}
88
89static CXSourceLocation makeLocation(const CXLoadedDiagnostic::Location *DLoc) {
90 // The lowest bit of ptr_data[0] is always set to 1 to indicate this
91 // is a persistent diagnostic.
92 uintptr_t V = (uintptr_t) DLoc;
93 V |= 0x1;
94 CXSourceLocation Loc = { { (void*) V, 0 }, 0 };
95 return Loc;
96}
97
98CXSourceLocation CXLoadedDiagnostic::getLocation() const {
99 // The lowest bit of ptr_data[0] is always set to 1 to indicate this
100 // is a persistent diagnostic.
101 return makeLocation(&DiagLoc);
102}
103
104CXString CXLoadedDiagnostic::getSpelling() const {
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000105 return cxstring::createRef(Spelling);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000106}
107
108CXString CXLoadedDiagnostic::getDiagnosticOption(CXString *Disable) const {
109 if (DiagOption.empty())
Dmitri Gribenko36a6dd02013-02-01 14:21:22 +0000110 return cxstring::createEmpty();
Ted Kremenekd010ba42011-11-10 08:43:12 +0000111
112 // FIXME: possibly refactor with logic in CXStoredDiagnostic.
113 if (Disable)
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000114 *Disable = cxstring::createDup((Twine("-Wno-") + DiagOption).str());
115 return cxstring::createDup((Twine("-W") + DiagOption).str());
Ted Kremenekd010ba42011-11-10 08:43:12 +0000116}
117
118unsigned CXLoadedDiagnostic::getCategory() const {
119 return category;
120}
121
Ted Kremenek26a6d492012-04-12 00:03:31 +0000122CXString CXLoadedDiagnostic::getCategoryText() const {
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000123 return cxstring::createDup(CategoryText);
Ted Kremenek26a6d492012-04-12 00:03:31 +0000124}
125
Ted Kremenekd010ba42011-11-10 08:43:12 +0000126unsigned CXLoadedDiagnostic::getNumRanges() const {
127 return Ranges.size();
128}
129
130CXSourceRange CXLoadedDiagnostic::getRange(unsigned Range) const {
131 assert(Range < Ranges.size());
132 return Ranges[Range];
133}
134
135unsigned CXLoadedDiagnostic::getNumFixIts() const {
136 return FixIts.size();
137}
138
139CXString CXLoadedDiagnostic::getFixIt(unsigned FixIt,
140 CXSourceRange *ReplacementRange) const {
141 assert(FixIt < FixIts.size());
142 if (ReplacementRange)
143 *ReplacementRange = FixIts[FixIt].first;
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000144 return cxstring::createRef(FixIts[FixIt].second);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000145}
146
147void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location,
148 CXFile *file,
149 unsigned int *line,
150 unsigned int *column,
151 unsigned int *offset) {
152
153
154 // CXSourceLocation consists of the following fields:
155 //
156 // void *ptr_data[2];
157 // unsigned int_data;
158 //
159 // The lowest bit of ptr_data[0] is always set to 1 to indicate this
160 // is a persistent diagnostic.
161 //
162 // For now, do the unoptimized approach and store the data in a side
163 // data structure. We can optimize this case later.
164
165 uintptr_t V = (uintptr_t) location.ptr_data[0];
166 assert((V & 0x1) == 1);
167 V &= ~(uintptr_t)1;
168
169 const Location &Loc = *((Location*)V);
170
171 if (file)
172 *file = Loc.file;
173 if (line)
174 *line = Loc.line;
175 if (column)
176 *column = Loc.column;
177 if (offset)
178 *offset = Loc.offset;
179}
180
181//===----------------------------------------------------------------------===//
182// Deserialize diagnostics.
183//===----------------------------------------------------------------------===//
184
Jordan Rose7ef1c382014-03-03 18:29:52 +0000185enum { MaxSupportedVersion = 2 };
Ted Kremenekd010ba42011-11-10 08:43:12 +0000186typedef SmallVector<uint64_t, 64> RecordData;
187enum LoadResult { Failure = 1, Success = 0 };
188enum StreamResult { Read_EndOfStream,
189 Read_BlockBegin,
190 Read_Failure,
191 Read_Record,
192 Read_BlockEnd };
193
194namespace {
195class DiagLoader {
196 enum CXLoadDiag_Error *error;
197 CXString *errorString;
198
199 void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
200 if (error)
201 *error = code;
202 if (errorString)
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000203 *errorString = cxstring::createDup(err);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000204 }
205
206 void reportInvalidFile(llvm::StringRef err) {
207 return reportBad(CXLoadDiag_InvalidFile, err);
208 }
209
210 LoadResult readMetaBlock(llvm::BitstreamCursor &Stream);
211
212 LoadResult readDiagnosticBlock(llvm::BitstreamCursor &Stream,
213 CXDiagnosticSetImpl &Diags,
214 CXLoadedDiagnosticSetImpl &TopDiags);
215
216 StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
217 llvm::StringRef errorContext,
218 unsigned &BlockOrRecordID,
Chris Lattnerc79fcfa2013-01-19 21:35:35 +0000219 bool atTopLevel = false);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000220
221
222 LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
223 Strings &strings, llvm::StringRef errorContext,
224 RecordData &Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000225 StringRef Blob,
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000226 bool allowEmptyString = false);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000227
228 LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000229 const char *&RetStr,
Ted Kremenekd010ba42011-11-10 08:43:12 +0000230 llvm::StringRef errorContext,
231 RecordData &Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000232 StringRef Blob,
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000233 bool allowEmptyString = false);
Ted Kremenekd010ba42011-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)
Dmitri Gribenko36a6dd02013-02-01 14:21:22 +0000249 *errorString = cxstring::createEmpty();
Ted Kremenekd010ba42011-11-10 08:43:12 +0000250 }
Ted Kremenek70394cf2011-11-11 15:19:48 +0000251
Ted Kremenekd010ba42011-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 Noblesmith1cd10692012-02-13 12:32:21 +0000262 OwningPtr<llvm::MemoryBuffer> Buffer;
Ted Kremenekd010ba42011-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 Lattnerc79fcfa2013-01-19 21:35:35 +0000287 OwningPtr<CXLoadedDiagnosticSetImpl> Diags(new CXLoadedDiagnosticSetImpl());
Ted Kremenekd010ba42011-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:
Ahmed Charles9a16beb2014-03-07 19:33:25 +0000295 return (CXDiagnosticSet)Diags.release();
Ted Kremenekd010ba42011-11-10 08:43:12 +0000296 case Read_Failure:
297 return 0;
298 case Read_Record:
299 llvm_unreachable("Top-level does not have records");
Ted Kremenekd010ba42011-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 Lattnerc79fcfa2013-01-19 21:35:35 +0000328 bool atTopLevel) {
Ted Kremenekd010ba42011-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;
Chris Lattner0e6c9402013-01-20 02:38:54 +0000425 unsigned recordID = Stream.readRecord(blockOrCode, Record);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000426
427 if (recordID == serialized_diags::RECORD_VERSION) {
428 if (Record.size() < 1) {
429 reportInvalidFile("malformed VERSION identifier in diagnostics file");
430 return Failure;
431 }
432 if (Record[0] > MaxSupportedVersion) {
Stefanus Du Toitb3318502013-03-01 21:41:22 +0000433 reportInvalidFile("diagnostics file is a newer version than the one "
Ted Kremenekd010ba42011-11-10 08:43:12 +0000434 "supported");
435 return Failure;
436 }
437 versionChecked = true;
438 }
439 }
440}
441
442LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000443 const char *&RetStr,
Ted Kremenekd010ba42011-11-10 08:43:12 +0000444 llvm::StringRef errorContext,
445 RecordData &Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000446 StringRef Blob,
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000447 bool allowEmptyString) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000448
449 // Basic buffer overflow check.
Chris Lattner0e6c9402013-01-20 02:38:54 +0000450 if (Blob.size() > 65536) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000451 reportInvalidFile(std::string("Out-of-bounds string in ") +
452 std::string(errorContext));
453 return Failure;
454 }
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000455
Chris Lattner0e6c9402013-01-20 02:38:54 +0000456 if (allowEmptyString && Record.size() >= 1 && Blob.size() == 0) {
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000457 RetStr = "";
458 return Success;
459 }
Ted Kremenekd010ba42011-11-10 08:43:12 +0000460
Chris Lattner0e6c9402013-01-20 02:38:54 +0000461 if (Record.size() < 1 || Blob.size() == 0) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000462 reportInvalidFile(std::string("Corrupted ") + std::string(errorContext)
463 + std::string(" entry"));
464 return Failure;
465 }
466
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000467 RetStr = TopDiags.copyString(Blob);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000468 return Success;
469}
470
471LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
472 Strings &strings,
473 llvm::StringRef errorContext,
474 RecordData &Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000475 StringRef Blob,
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000476 bool allowEmptyString) {
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000477 const char *RetStr;
Chris Lattner0e6c9402013-01-20 02:38:54 +0000478 if (readString(TopDiags, RetStr, errorContext, Record, Blob,
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000479 allowEmptyString))
Ted Kremenekd010ba42011-11-10 08:43:12 +0000480 return Failure;
481 strings[Record[0]] = RetStr;
482 return Success;
483}
484
485LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
486 RecordData &Record, unsigned &offset,
487 CXLoadedDiagnostic::Location &Loc) {
488 if (Record.size() < offset + 3) {
489 reportInvalidFile("Corrupted source location");
490 return Failure;
491 }
492
493 unsigned fileID = Record[offset++];
494 if (fileID == 0) {
495 // Sentinel value.
496 Loc.file = 0;
497 Loc.line = 0;
498 Loc.column = 0;
499 Loc.offset = 0;
500 return Success;
501 }
502
503 const FileEntry *FE = TopDiags.Files[fileID];
504 if (!FE) {
505 reportInvalidFile("Corrupted file entry in source location");
506 return Failure;
507 }
David Greene4320e5e2013-01-15 22:09:48 +0000508 Loc.file = const_cast<FileEntry *>(FE);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000509 Loc.line = Record[offset++];
510 Loc.column = Record[offset++];
511 Loc.offset = Record[offset++];
512 return Success;
513}
514
515LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags,
516 RecordData &Record,
517 unsigned int RecStartIdx,
518 CXSourceRange &SR) {
519 CXLoadedDiagnostic::Location *Start, *End;
520 Start = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
521 End = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
522
523 if (readLocation(TopDiags, Record, RecStartIdx, *Start))
524 return Failure;
525 if (readLocation(TopDiags, Record, RecStartIdx, *End))
526 return Failure;
527
528 CXSourceLocation startLoc = makeLocation(Start);
529 CXSourceLocation endLoc = makeLocation(End);
530 SR = clang_getRange(startLoc, endLoc);
531 return Success;
532}
533
534LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
535 CXDiagnosticSetImpl &Diags,
536 CXLoadedDiagnosticSetImpl &TopDiags){
537
538 if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
539 reportInvalidFile("malformed diagnostic block");
540 return Failure;
541 }
542
Dylan Noblesmith1cd10692012-02-13 12:32:21 +0000543 OwningPtr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic());
Ted Kremenekd010ba42011-11-10 08:43:12 +0000544 RecordData Record;
545
546 while (true) {
547 unsigned blockOrCode = 0;
548 StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block",
549 blockOrCode);
550 switch (Res) {
551 case Read_EndOfStream:
552 llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock");
Ted Kremenekd010ba42011-11-10 08:43:12 +0000553 case Read_Failure:
554 return Failure;
555 case Read_BlockBegin: {
556 // The only blocks we care about are subdiagnostics.
557 if (blockOrCode != serialized_diags::BLOCK_DIAG) {
558 if (!Stream.SkipBlock()) {
559 reportInvalidFile("Invalid subblock in Diagnostics block");
560 return Failure;
561 }
562 } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(),
563 TopDiags)) {
564 return Failure;
565 }
566
567 continue;
568 }
569 case Read_BlockEnd:
Ahmed Charles9a16beb2014-03-07 19:33:25 +0000570 Diags.appendDiagnostic(D.release());
Ted Kremenekd010ba42011-11-10 08:43:12 +0000571 return Success;
572 case Read_Record:
573 break;
574 }
575
576 // Read the record.
577 Record.clear();
Chris Lattner0e6c9402013-01-20 02:38:54 +0000578 StringRef Blob;
579 unsigned recID = Stream.readRecord(blockOrCode, Record, &Blob);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000580
581 if (recID < serialized_diags::RECORD_FIRST ||
582 recID > serialized_diags::RECORD_LAST)
583 continue;
584
585 switch ((serialized_diags::RecordIDs)recID) {
586 case serialized_diags::RECORD_VERSION:
587 continue;
588 case serialized_diags::RECORD_CATEGORY:
589 if (readString(TopDiags, TopDiags.Categories, "category", Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000590 Blob, /* allowEmptyString */ true))
Ted Kremenekd010ba42011-11-10 08:43:12 +0000591 return Failure;
592 continue;
593
594 case serialized_diags::RECORD_DIAG_FLAG:
595 if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000596 Blob))
Ted Kremenekd010ba42011-11-10 08:43:12 +0000597 return Failure;
598 continue;
599
600 case serialized_diags::RECORD_FILENAME: {
601 if (readString(TopDiags, TopDiags.FileNames, "filename", Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000602 Blob))
Ted Kremenekd010ba42011-11-10 08:43:12 +0000603 return Failure;
604
605 if (Record.size() < 3) {
606 reportInvalidFile("Invalid file entry");
607 return Failure;
608 }
609
610 const FileEntry *FE =
611 TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]],
612 /* size */ Record[1],
613 /* time */ Record[2]);
614
615 TopDiags.Files[Record[0]] = FE;
616 continue;
617 }
618
619 case serialized_diags::RECORD_SOURCE_RANGE: {
620 CXSourceRange SR;
621 if (readRange(TopDiags, Record, 0, SR))
622 return Failure;
623 D->Ranges.push_back(SR);
624 continue;
625 }
626
627 case serialized_diags::RECORD_FIXIT: {
628 CXSourceRange SR;
629 if (readRange(TopDiags, Record, 0, SR))
630 return Failure;
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000631 const char *RetStr;
Chris Lattner0e6c9402013-01-20 02:38:54 +0000632 if (readString(TopDiags, RetStr, "FIXIT", Record, Blob,
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000633 /* allowEmptyString */ true))
Ted Kremenekd010ba42011-11-10 08:43:12 +0000634 return Failure;
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000635 D->FixIts.push_back(std::make_pair(SR, RetStr));
Ted Kremenek70394cf2011-11-11 15:19:48 +0000636 continue;
Ted Kremenekd010ba42011-11-10 08:43:12 +0000637 }
638
639 case serialized_diags::RECORD_DIAG: {
640 D->severity = Record[0];
641 unsigned offset = 1;
642 if (readLocation(TopDiags, Record, offset, D->DiagLoc))
643 return Failure;
644 D->category = Record[offset++];
645 unsigned diagFlag = Record[offset++];
646 D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : "";
Ted Kremenek26a6d492012-04-12 00:03:31 +0000647 D->CategoryText = D->category ? TopDiags.Categories[D->category] : "";
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000648 D->Spelling = TopDiags.copyString(Blob);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000649 continue;
650 }
651 }
652 }
653}
654
655extern "C" {
656CXDiagnosticSet clang_loadDiagnostics(const char *file,
657 enum CXLoadDiag_Error *error,
658 CXString *errorString) {
659 DiagLoader L(error, errorString);
660 return L.load(file);
661}
662} // end extern 'C'.