blob: 8385f242d4498e9f44a3f3e6e898f9e88573f8e7 [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)
Jordan Rose7ef1c382014-03-03 18:29:52 +000082#undef CASE
Alp Toker87d39752014-04-26 14:43:53 +000083 // The 'Remark' level isn't represented in the stable API.
84 case serialized_diags::Remark: return CXDiagnostic_Warning;
Ted Kremenekd010ba42011-11-10 08:43:12 +000085 }
86
87 llvm_unreachable("Invalid diagnostic level");
Ted Kremenekd010ba42011-11-10 08:43:12 +000088}
89
90static CXSourceLocation makeLocation(const CXLoadedDiagnostic::Location *DLoc) {
91 // The lowest bit of ptr_data[0] is always set to 1 to indicate this
92 // is a persistent diagnostic.
93 uintptr_t V = (uintptr_t) DLoc;
94 V |= 0x1;
95 CXSourceLocation Loc = { { (void*) V, 0 }, 0 };
96 return Loc;
97}
98
99CXSourceLocation CXLoadedDiagnostic::getLocation() const {
100 // The lowest bit of ptr_data[0] is always set to 1 to indicate this
101 // is a persistent diagnostic.
102 return makeLocation(&DiagLoc);
103}
104
105CXString CXLoadedDiagnostic::getSpelling() const {
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000106 return cxstring::createRef(Spelling);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000107}
108
109CXString CXLoadedDiagnostic::getDiagnosticOption(CXString *Disable) const {
110 if (DiagOption.empty())
Dmitri Gribenko36a6dd02013-02-01 14:21:22 +0000111 return cxstring::createEmpty();
Ted Kremenekd010ba42011-11-10 08:43:12 +0000112
113 // FIXME: possibly refactor with logic in CXStoredDiagnostic.
114 if (Disable)
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000115 *Disable = cxstring::createDup((Twine("-Wno-") + DiagOption).str());
116 return cxstring::createDup((Twine("-W") + DiagOption).str());
Ted Kremenekd010ba42011-11-10 08:43:12 +0000117}
118
119unsigned CXLoadedDiagnostic::getCategory() const {
120 return category;
121}
122
Ted Kremenek26a6d492012-04-12 00:03:31 +0000123CXString CXLoadedDiagnostic::getCategoryText() const {
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000124 return cxstring::createDup(CategoryText);
Ted Kremenek26a6d492012-04-12 00:03:31 +0000125}
126
Ted Kremenekd010ba42011-11-10 08:43:12 +0000127unsigned CXLoadedDiagnostic::getNumRanges() const {
128 return Ranges.size();
129}
130
131CXSourceRange CXLoadedDiagnostic::getRange(unsigned Range) const {
132 assert(Range < Ranges.size());
133 return Ranges[Range];
134}
135
136unsigned CXLoadedDiagnostic::getNumFixIts() const {
137 return FixIts.size();
138}
139
140CXString CXLoadedDiagnostic::getFixIt(unsigned FixIt,
141 CXSourceRange *ReplacementRange) const {
142 assert(FixIt < FixIts.size());
143 if (ReplacementRange)
144 *ReplacementRange = FixIts[FixIt].first;
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000145 return cxstring::createRef(FixIts[FixIt].second);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000146}
147
148void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location,
149 CXFile *file,
150 unsigned int *line,
151 unsigned int *column,
152 unsigned int *offset) {
153
154
155 // CXSourceLocation consists of the following fields:
156 //
157 // void *ptr_data[2];
158 // unsigned int_data;
159 //
160 // The lowest bit of ptr_data[0] is always set to 1 to indicate this
161 // is a persistent diagnostic.
162 //
163 // For now, do the unoptimized approach and store the data in a side
164 // data structure. We can optimize this case later.
165
166 uintptr_t V = (uintptr_t) location.ptr_data[0];
167 assert((V & 0x1) == 1);
168 V &= ~(uintptr_t)1;
169
170 const Location &Loc = *((Location*)V);
171
172 if (file)
173 *file = Loc.file;
174 if (line)
175 *line = Loc.line;
176 if (column)
177 *column = Loc.column;
178 if (offset)
179 *offset = Loc.offset;
180}
181
182//===----------------------------------------------------------------------===//
183// Deserialize diagnostics.
184//===----------------------------------------------------------------------===//
185
Jordan Rose7ef1c382014-03-03 18:29:52 +0000186enum { MaxSupportedVersion = 2 };
Ted Kremenekd010ba42011-11-10 08:43:12 +0000187typedef SmallVector<uint64_t, 64> RecordData;
188enum LoadResult { Failure = 1, Success = 0 };
189enum StreamResult { Read_EndOfStream,
190 Read_BlockBegin,
191 Read_Failure,
192 Read_Record,
193 Read_BlockEnd };
194
195namespace {
196class DiagLoader {
197 enum CXLoadDiag_Error *error;
198 CXString *errorString;
199
200 void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
201 if (error)
202 *error = code;
203 if (errorString)
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000204 *errorString = cxstring::createDup(err);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000205 }
206
207 void reportInvalidFile(llvm::StringRef err) {
208 return reportBad(CXLoadDiag_InvalidFile, err);
209 }
210
211 LoadResult readMetaBlock(llvm::BitstreamCursor &Stream);
212
213 LoadResult readDiagnosticBlock(llvm::BitstreamCursor &Stream,
214 CXDiagnosticSetImpl &Diags,
215 CXLoadedDiagnosticSetImpl &TopDiags);
216
217 StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
218 llvm::StringRef errorContext,
219 unsigned &BlockOrRecordID,
Chris Lattnerc79fcfa2013-01-19 21:35:35 +0000220 bool atTopLevel = false);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000221
222
223 LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
224 Strings &strings, llvm::StringRef errorContext,
225 RecordData &Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000226 StringRef Blob,
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000227 bool allowEmptyString = false);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000228
229 LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000230 const char *&RetStr,
Ted Kremenekd010ba42011-11-10 08:43:12 +0000231 llvm::StringRef errorContext,
232 RecordData &Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000233 StringRef Blob,
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000234 bool allowEmptyString = false);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000235
236 LoadResult readRange(CXLoadedDiagnosticSetImpl &TopDiags,
237 RecordData &Record, unsigned RecStartIdx,
238 CXSourceRange &SR);
239
240 LoadResult readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
241 RecordData &Record, unsigned &offset,
242 CXLoadedDiagnostic::Location &Loc);
243
244public:
245 DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
246 : error(e), errorString(es) {
247 if (error)
248 *error = CXLoadDiag_None;
249 if (errorString)
Dmitri Gribenko36a6dd02013-02-01 14:21:22 +0000250 *errorString = cxstring::createEmpty();
Ted Kremenekd010ba42011-11-10 08:43:12 +0000251 }
Ted Kremenek70394cf2011-11-11 15:19:48 +0000252
Ted Kremenekd010ba42011-11-10 08:43:12 +0000253 CXDiagnosticSet load(const char *file);
254};
255}
256
257CXDiagnosticSet DiagLoader::load(const char *file) {
258 // Open the diagnostics file.
259 std::string ErrStr;
260 FileSystemOptions FO;
261 FileManager FileMgr(FO);
262
Ahmed Charlesb8984322014-03-07 20:03:18 +0000263 std::unique_ptr<llvm::MemoryBuffer> Buffer;
Ted Kremenekd010ba42011-11-10 08:43:12 +0000264 Buffer.reset(FileMgr.getBufferForFile(file));
265
266 if (!Buffer) {
267 reportBad(CXLoadDiag_CannotLoad, ErrStr);
268 return 0;
269 }
270
271 llvm::BitstreamReader StreamFile;
272 StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
273 (const unsigned char *)Buffer->getBufferEnd());
274
275 llvm::BitstreamCursor Stream;
276 Stream.init(StreamFile);
277
278 // Sniff for the signature.
279 if (Stream.Read(8) != 'D' ||
280 Stream.Read(8) != 'I' ||
281 Stream.Read(8) != 'A' ||
282 Stream.Read(8) != 'G') {
283 reportBad(CXLoadDiag_InvalidFile,
284 "Bad header in diagnostics file");
285 return 0;
286 }
287
Ahmed Charlesb8984322014-03-07 20:03:18 +0000288 std::unique_ptr<CXLoadedDiagnosticSetImpl> Diags(
289 new CXLoadedDiagnosticSetImpl());
Ted Kremenekd010ba42011-11-10 08:43:12 +0000290
291 while (true) {
292 unsigned BlockID = 0;
293 StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level",
294 BlockID, true);
295 switch (Res) {
296 case Read_EndOfStream:
Ahmed Charles9a16beb2014-03-07 19:33:25 +0000297 return (CXDiagnosticSet)Diags.release();
Ted Kremenekd010ba42011-11-10 08:43:12 +0000298 case Read_Failure:
299 return 0;
300 case Read_Record:
301 llvm_unreachable("Top-level does not have records");
Ted Kremenekd010ba42011-11-10 08:43:12 +0000302 case Read_BlockEnd:
303 continue;
304 case Read_BlockBegin:
305 break;
306 }
307
308 switch (BlockID) {
309 case serialized_diags::BLOCK_META:
310 if (readMetaBlock(Stream))
311 return 0;
312 break;
313 case serialized_diags::BLOCK_DIAG:
314 if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get()))
315 return 0;
316 break;
317 default:
318 if (!Stream.SkipBlock()) {
319 reportInvalidFile("Malformed block at top-level of diagnostics file");
320 return 0;
321 }
322 break;
323 }
324 }
325}
326
327StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
328 llvm::StringRef errorContext,
329 unsigned &blockOrRecordID,
Chris Lattnerc79fcfa2013-01-19 21:35:35 +0000330 bool atTopLevel) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000331
332 blockOrRecordID = 0;
333
334 while (!Stream.AtEndOfStream()) {
335 unsigned Code = Stream.ReadCode();
336
337 // Handle the top-level specially.
338 if (atTopLevel) {
339 if (Code == llvm::bitc::ENTER_SUBBLOCK) {
340 unsigned BlockID = Stream.ReadSubBlockID();
341 if (BlockID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
342 if (Stream.ReadBlockInfoBlock()) {
343 reportInvalidFile("Malformed BlockInfoBlock in diagnostics file");
344 return Read_Failure;
345 }
346 continue;
347 }
348 blockOrRecordID = BlockID;
349 return Read_BlockBegin;
350 }
351 reportInvalidFile("Only blocks can appear at the top of a "
352 "diagnostic file");
353 return Read_Failure;
354 }
355
356 switch ((llvm::bitc::FixedAbbrevIDs)Code) {
357 case llvm::bitc::ENTER_SUBBLOCK:
358 blockOrRecordID = Stream.ReadSubBlockID();
359 return Read_BlockBegin;
360
361 case llvm::bitc::END_BLOCK:
362 if (Stream.ReadBlockEnd()) {
363 reportInvalidFile("Cannot read end of block");
364 return Read_Failure;
365 }
366 return Read_BlockEnd;
367
368 case llvm::bitc::DEFINE_ABBREV:
369 Stream.ReadAbbrevRecord();
370 continue;
371
372 case llvm::bitc::UNABBREV_RECORD:
373 reportInvalidFile("Diagnostics file should have no unabbreviated "
374 "records");
375 return Read_Failure;
376
377 default:
378 // We found a record.
379 blockOrRecordID = Code;
380 return Read_Record;
381 }
382 }
383
384 if (atTopLevel)
385 return Read_EndOfStream;
386
387 reportInvalidFile(Twine("Premature end of diagnostics file within ").str() +
388 errorContext.str());
389 return Read_Failure;
390}
391
392LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
393 if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
394 reportInvalidFile("Malformed metadata block");
395 return Failure;
396 }
397
398 bool versionChecked = false;
399
400 while (true) {
401 unsigned blockOrCode = 0;
402 StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block",
403 blockOrCode);
404
405 switch(Res) {
406 case Read_EndOfStream:
407 llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock");
408 case Read_Failure:
409 return Failure;
410 case Read_Record:
411 break;
412 case Read_BlockBegin:
413 if (Stream.SkipBlock()) {
414 reportInvalidFile("Malformed metadata block");
415 return Failure;
416 }
417 case Read_BlockEnd:
418 if (!versionChecked) {
419 reportInvalidFile("Diagnostics file does not contain version"
420 " information");
421 return Failure;
422 }
423 return Success;
424 }
425
426 RecordData Record;
Chris Lattner0e6c9402013-01-20 02:38:54 +0000427 unsigned recordID = Stream.readRecord(blockOrCode, Record);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000428
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) {
Stefanus Du Toitb3318502013-03-01 21:41:22 +0000435 reportInvalidFile("diagnostics file is a newer version than the one "
Ted Kremenekd010ba42011-11-10 08:43:12 +0000436 "supported");
437 return Failure;
438 }
439 versionChecked = true;
440 }
441 }
442}
443
444LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000445 const char *&RetStr,
Ted Kremenekd010ba42011-11-10 08:43:12 +0000446 llvm::StringRef errorContext,
447 RecordData &Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000448 StringRef Blob,
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000449 bool allowEmptyString) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000450
451 // Basic buffer overflow check.
Chris Lattner0e6c9402013-01-20 02:38:54 +0000452 if (Blob.size() > 65536) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000453 reportInvalidFile(std::string("Out-of-bounds string in ") +
454 std::string(errorContext));
455 return Failure;
456 }
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000457
Chris Lattner0e6c9402013-01-20 02:38:54 +0000458 if (allowEmptyString && Record.size() >= 1 && Blob.size() == 0) {
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000459 RetStr = "";
460 return Success;
461 }
Ted Kremenekd010ba42011-11-10 08:43:12 +0000462
Chris Lattner0e6c9402013-01-20 02:38:54 +0000463 if (Record.size() < 1 || Blob.size() == 0) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000464 reportInvalidFile(std::string("Corrupted ") + std::string(errorContext)
465 + std::string(" entry"));
466 return Failure;
467 }
468
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000469 RetStr = TopDiags.copyString(Blob);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000470 return Success;
471}
472
473LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
474 Strings &strings,
475 llvm::StringRef errorContext,
476 RecordData &Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000477 StringRef Blob,
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000478 bool allowEmptyString) {
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000479 const char *RetStr;
Chris Lattner0e6c9402013-01-20 02:38:54 +0000480 if (readString(TopDiags, RetStr, errorContext, Record, Blob,
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000481 allowEmptyString))
Ted Kremenekd010ba42011-11-10 08:43:12 +0000482 return Failure;
483 strings[Record[0]] = RetStr;
484 return Success;
485}
486
487LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
488 RecordData &Record, unsigned &offset,
489 CXLoadedDiagnostic::Location &Loc) {
490 if (Record.size() < offset + 3) {
491 reportInvalidFile("Corrupted source location");
492 return Failure;
493 }
494
495 unsigned fileID = Record[offset++];
496 if (fileID == 0) {
497 // Sentinel value.
498 Loc.file = 0;
499 Loc.line = 0;
500 Loc.column = 0;
501 Loc.offset = 0;
502 return Success;
503 }
504
505 const FileEntry *FE = TopDiags.Files[fileID];
506 if (!FE) {
507 reportInvalidFile("Corrupted file entry in source location");
508 return Failure;
509 }
David Greene4320e5e2013-01-15 22:09:48 +0000510 Loc.file = const_cast<FileEntry *>(FE);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000511 Loc.line = Record[offset++];
512 Loc.column = Record[offset++];
513 Loc.offset = Record[offset++];
514 return Success;
515}
516
517LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags,
518 RecordData &Record,
519 unsigned int RecStartIdx,
520 CXSourceRange &SR) {
521 CXLoadedDiagnostic::Location *Start, *End;
522 Start = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
523 End = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
524
525 if (readLocation(TopDiags, Record, RecStartIdx, *Start))
526 return Failure;
527 if (readLocation(TopDiags, Record, RecStartIdx, *End))
528 return Failure;
529
530 CXSourceLocation startLoc = makeLocation(Start);
531 CXSourceLocation endLoc = makeLocation(End);
532 SR = clang_getRange(startLoc, endLoc);
533 return Success;
534}
535
536LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
537 CXDiagnosticSetImpl &Diags,
538 CXLoadedDiagnosticSetImpl &TopDiags){
539
540 if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
541 reportInvalidFile("malformed diagnostic block");
542 return Failure;
543 }
Ahmed Charlesb8984322014-03-07 20:03:18 +0000544
545 std::unique_ptr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic());
Ted Kremenekd010ba42011-11-10 08:43:12 +0000546 RecordData Record;
547
548 while (true) {
549 unsigned blockOrCode = 0;
550 StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block",
551 blockOrCode);
552 switch (Res) {
553 case Read_EndOfStream:
554 llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock");
Ted Kremenekd010ba42011-11-10 08:43:12 +0000555 case Read_Failure:
556 return Failure;
557 case Read_BlockBegin: {
558 // The only blocks we care about are subdiagnostics.
559 if (blockOrCode != serialized_diags::BLOCK_DIAG) {
560 if (!Stream.SkipBlock()) {
561 reportInvalidFile("Invalid subblock in Diagnostics block");
562 return Failure;
563 }
564 } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(),
565 TopDiags)) {
566 return Failure;
567 }
568
569 continue;
570 }
571 case Read_BlockEnd:
Ahmed Charles9a16beb2014-03-07 19:33:25 +0000572 Diags.appendDiagnostic(D.release());
Ted Kremenekd010ba42011-11-10 08:43:12 +0000573 return Success;
574 case Read_Record:
575 break;
576 }
577
578 // Read the record.
579 Record.clear();
Chris Lattner0e6c9402013-01-20 02:38:54 +0000580 StringRef Blob;
581 unsigned recID = Stream.readRecord(blockOrCode, Record, &Blob);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000582
583 if (recID < serialized_diags::RECORD_FIRST ||
584 recID > serialized_diags::RECORD_LAST)
585 continue;
586
587 switch ((serialized_diags::RecordIDs)recID) {
588 case serialized_diags::RECORD_VERSION:
589 continue;
590 case serialized_diags::RECORD_CATEGORY:
591 if (readString(TopDiags, TopDiags.Categories, "category", Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000592 Blob, /* allowEmptyString */ true))
Ted Kremenekd010ba42011-11-10 08:43:12 +0000593 return Failure;
594 continue;
595
596 case serialized_diags::RECORD_DIAG_FLAG:
597 if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000598 Blob))
Ted Kremenekd010ba42011-11-10 08:43:12 +0000599 return Failure;
600 continue;
601
602 case serialized_diags::RECORD_FILENAME: {
603 if (readString(TopDiags, TopDiags.FileNames, "filename", Record,
Chris Lattner0e6c9402013-01-20 02:38:54 +0000604 Blob))
Ted Kremenekd010ba42011-11-10 08:43:12 +0000605 return Failure;
606
607 if (Record.size() < 3) {
608 reportInvalidFile("Invalid file entry");
609 return Failure;
610 }
611
612 const FileEntry *FE =
613 TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]],
614 /* size */ Record[1],
615 /* time */ Record[2]);
616
617 TopDiags.Files[Record[0]] = FE;
618 continue;
619 }
620
621 case serialized_diags::RECORD_SOURCE_RANGE: {
622 CXSourceRange SR;
623 if (readRange(TopDiags, Record, 0, SR))
624 return Failure;
625 D->Ranges.push_back(SR);
626 continue;
627 }
628
629 case serialized_diags::RECORD_FIXIT: {
630 CXSourceRange SR;
631 if (readRange(TopDiags, Record, 0, SR))
632 return Failure;
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000633 const char *RetStr;
Chris Lattner0e6c9402013-01-20 02:38:54 +0000634 if (readString(TopDiags, RetStr, "FIXIT", Record, Blob,
Ted Kremenek6cdff0a2011-11-29 00:30:52 +0000635 /* allowEmptyString */ true))
Ted Kremenekd010ba42011-11-10 08:43:12 +0000636 return Failure;
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000637 D->FixIts.push_back(std::make_pair(SR, RetStr));
Ted Kremenek70394cf2011-11-11 15:19:48 +0000638 continue;
Ted Kremenekd010ba42011-11-10 08:43:12 +0000639 }
640
641 case serialized_diags::RECORD_DIAG: {
642 D->severity = Record[0];
643 unsigned offset = 1;
644 if (readLocation(TopDiags, Record, offset, D->DiagLoc))
645 return Failure;
646 D->category = Record[offset++];
647 unsigned diagFlag = Record[offset++];
648 D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : "";
Ted Kremenek26a6d492012-04-12 00:03:31 +0000649 D->CategoryText = D->category ? TopDiags.Categories[D->category] : "";
Dmitri Gribenko7d098082013-02-18 19:50:38 +0000650 D->Spelling = TopDiags.copyString(Blob);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000651 continue;
652 }
653 }
654 }
655}
656
657extern "C" {
658CXDiagnosticSet clang_loadDiagnostics(const char *file,
659 enum CXLoadDiag_Error *error,
660 CXString *errorString) {
661 DiagLoader L(error, errorString);
662 return L.load(file);
663}
664} // end extern 'C'.