clang  3.7.0
SerializedDiagnosticReader.cpp
Go to the documentation of this file.
1 //===--- SerializedDiagnosticReader.cpp - Reads diagnostics ---------------===//
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 
13 #include "llvm/Support/ManagedStatic.h"
14 #include "llvm/Support/MemoryBuffer.h"
15 
16 using namespace clang;
17 using namespace clang::serialized_diags;
18 
19 std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
20  // Open the diagnostics file.
22  FileManager FileMgr(FO);
23 
24  auto Buffer = FileMgr.getBufferForFile(File);
25  if (!Buffer)
26  return SDError::CouldNotLoad;
27 
28  llvm::BitstreamReader StreamFile;
29  StreamFile.init((const unsigned char *)(*Buffer)->getBufferStart(),
30  (const unsigned char *)(*Buffer)->getBufferEnd());
31 
32  llvm::BitstreamCursor Stream(StreamFile);
33 
34  // Sniff for the signature.
35  if (Stream.Read(8) != 'D' ||
36  Stream.Read(8) != 'I' ||
37  Stream.Read(8) != 'A' ||
38  Stream.Read(8) != 'G')
40 
41  // Read the top level blocks.
42  while (!Stream.AtEndOfStream()) {
43  if (Stream.ReadCode() != llvm::bitc::ENTER_SUBBLOCK)
45 
46  std::error_code EC;
47  switch (Stream.ReadSubBlockID()) {
48  case llvm::bitc::BLOCKINFO_BLOCK_ID:
49  if (Stream.ReadBlockInfoBlock())
51  continue;
52  case BLOCK_META:
53  if ((EC = readMetaBlock(Stream)))
54  return EC;
55  continue;
56  case BLOCK_DIAG:
57  if ((EC = readDiagnosticBlock(Stream)))
58  return EC;
59  continue;
60  default:
61  if (!Stream.SkipBlock())
63  continue;
64  }
65  }
66  return std::error_code();
67 }
68 
70  Record = 1,
71  BlockEnd,
72  BlockBegin
73 };
74 
75 llvm::ErrorOr<SerializedDiagnosticReader::Cursor>
76 SerializedDiagnosticReader::skipUntilRecordOrBlock(
77  llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
78  BlockOrRecordID = 0;
79 
80  while (!Stream.AtEndOfStream()) {
81  unsigned Code = Stream.ReadCode();
82 
83  switch ((llvm::bitc::FixedAbbrevIDs)Code) {
84  case llvm::bitc::ENTER_SUBBLOCK:
85  BlockOrRecordID = Stream.ReadSubBlockID();
86  return Cursor::BlockBegin;
87 
88  case llvm::bitc::END_BLOCK:
89  if (Stream.ReadBlockEnd())
91  return Cursor::BlockEnd;
92 
93  case llvm::bitc::DEFINE_ABBREV:
94  Stream.ReadAbbrevRecord();
95  continue;
96 
97  case llvm::bitc::UNABBREV_RECORD:
99 
100  default:
101  // We found a record.
102  BlockOrRecordID = Code;
103  return Cursor::Record;
104  }
105  }
106 
108 }
109 
110 std::error_code
111 SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
112  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META))
114 
115  bool VersionChecked = false;
116 
117  while (true) {
118  unsigned BlockOrCode = 0;
119  llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
120  if (!Res)
121  Res.getError();
122 
123  switch (Res.get()) {
124  case Cursor::Record:
125  break;
126  case Cursor::BlockBegin:
127  if (Stream.SkipBlock())
129  case Cursor::BlockEnd:
130  if (!VersionChecked)
132  return std::error_code();
133  }
134 
136  unsigned RecordID = Stream.readRecord(BlockOrCode, Record);
137 
138  if (RecordID == RECORD_VERSION) {
139  if (Record.size() < 1)
141  if (Record[0] > VersionNumber)
143  VersionChecked = true;
144  }
145  }
146 }
147 
148 std::error_code
149 SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
150  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG))
152 
153  std::error_code EC;
154  if ((EC = visitStartOfDiagnostic()))
155  return EC;
156 
158  while (true) {
159  unsigned BlockOrCode = 0;
160  llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
161  if (!Res)
162  Res.getError();
163 
164  switch (Res.get()) {
165  case Cursor::BlockBegin:
166  // The only blocks we care about are subdiagnostics.
167  if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
168  if ((EC = readDiagnosticBlock(Stream)))
169  return EC;
170  } else if (!Stream.SkipBlock())
172  continue;
173  case Cursor::BlockEnd:
174  if ((EC = visitEndOfDiagnostic()))
175  return EC;
176  return std::error_code();
177  case Cursor::Record:
178  break;
179  }
180 
181  // Read the record.
182  Record.clear();
183  StringRef Blob;
184  unsigned RecID = Stream.readRecord(BlockOrCode, Record, &Blob);
185 
186  if (RecID < serialized_diags::RECORD_FIRST ||
188  continue;
189 
190  switch ((RecordIDs)RecID) {
191  case RECORD_CATEGORY:
192  // A category has ID and name size.
193  if (Record.size() != 2)
195  if ((EC = visitCategoryRecord(Record[0], Blob)))
196  return EC;
197  continue;
198  case RECORD_DIAG:
199  // A diagnostic has severity, location (4), category, flag, and message
200  // size.
201  if (Record.size() != 8)
203  if ((EC = visitDiagnosticRecord(
204  Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
205  Record[5], Record[6], Blob)))
206  return EC;
207  continue;
208  case RECORD_DIAG_FLAG:
209  // A diagnostic flag has ID and name size.
210  if (Record.size() != 2)
212  if ((EC = visitDiagFlagRecord(Record[0], Blob)))
213  return EC;
214  continue;
215  case RECORD_FILENAME:
216  // A filename has ID, size, timestamp, and name size. The size and
217  // timestamp are legacy fields that are always zero these days.
218  if (Record.size() != 4)
220  if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
221  return EC;
222  continue;
223  case RECORD_FIXIT:
224  // A fixit has two locations (4 each) and message size.
225  if (Record.size() != 9)
227  if ((EC = visitFixitRecord(
228  Location(Record[0], Record[1], Record[2], Record[3]),
229  Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
230  return EC;
231  continue;
232  case RECORD_SOURCE_RANGE:
233  // A source range is two locations (4 each).
234  if (Record.size() != 8)
236  if ((EC = visitSourceRangeRecord(
237  Location(Record[0], Record[1], Record[2], Record[3]),
238  Location(Record[4], Record[5], Record[6], Record[7]))))
239  return EC;
240  continue;
241  case RECORD_VERSION:
242  // A version is just a number.
243  if (Record.size() != 1)
245  if ((EC = visitVersionRecord(Record[0])))
246  return EC;
247  continue;
248  }
249  }
250 }
251 
252 namespace {
253 class SDErrorCategoryType final : public std::error_category {
254  const char *name() const LLVM_NOEXCEPT override {
255  return "clang.serialized_diags";
256  }
257  std::string message(int IE) const override {
258  SDError E = static_cast<SDError>(IE);
259  switch (E) {
261  return "Failed to open diagnostics file";
263  return "Invalid diagnostics signature";
265  return "Parse error reading diagnostics";
267  return "Malformed block at top-level of diagnostics";
269  return "Malformed sub-block in a diagnostic";
271  return "Malformed BlockInfo block";
273  return "Malformed Metadata block";
275  return "Malformed Diagnostic block";
277  return "Malformed Diagnostic record";
279  return "No version provided in diagnostics";
281  return "Unsupported diagnostics version";
283  return "Bitcode constructs that are not supported in diagnostics appear";
285  return "Generic error occurred while handling a record";
286  }
287  llvm_unreachable("Unknown error type!");
288  }
289 };
290 }
291 
292 static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;
293 const std::error_category &clang::serialized_diags::SDErrorCategory() {
294  return *ErrorCategory;
295 }
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:115
Defines the clang::FileManager interface and associated types.
virtual std::error_code visitStartOfDiagnostic()
Visit the start of a diagnostic block.
virtual std::error_code visitSourceRangeRecord(const Location &Start, const Location &End)
Visit a source range.
std::error_code readDiagnostics(StringRef File)
Read the diagnostics in File.
virtual std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name)
Visit a flag. This associates the flag's ID to a Name.
virtual std::error_code visitVersionRecord(unsigned Version)
Visit the version of the set of diagnostics.
virtual std::error_code visitFixitRecord(const Location &Start, const Location &End, StringRef Text)
Visit a fixit hint.
A location that is represented in the serialized diagnostics.
virtual std::error_code visitCategoryRecord(unsigned ID, StringRef Name)
Visit a category. This associates the category ID to a Name.
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const FileEntry *Entry, bool isVolatile=false, bool ShouldCloseOpenFile=true)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful, otherwise returning null.
static llvm::ManagedStatic< SDErrorCategoryType > ErrorCategory
Keeps track of options that affect how file operations are performed.
virtual std::error_code visitFilenameRecord(unsigned ID, unsigned Size, unsigned Timestamp, StringRef Name)
Visit a filename. This associates the file's ID to a Name.
const std::error_category & SDErrorCategory()
virtual std::error_code visitEndOfDiagnostic()
Visit the end of a diagnostic block.
The this block acts as a container for all the information for a specific diagnostic.
A top-level block which represents any meta data associated with the diagostics, including versioning...
virtual std::error_code visitDiagnosticRecord(unsigned Severity, const Location &Location, unsigned Category, unsigned Flag, StringRef Message)
Visit a diagnostic.