clang  8.0.0svn
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 
14 #include "llvm/ADT/Optional.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Bitcode/BitCodes.h"
18 #include "llvm/Bitcode/BitstreamReader.h"
19 #include "llvm/Support/Compiler.h"
20 #include "llvm/Support/ErrorHandling.h"
21 #include "llvm/Support/ErrorOr.h"
22 #include "llvm/Support/ManagedStatic.h"
23 #include <cstdint>
24 #include <system_error>
25 
26 using namespace clang;
27 using namespace serialized_diags;
28 
29 std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
30  // Open the diagnostics file.
32  FileManager FileMgr(FO);
33 
34  auto Buffer = FileMgr.getBufferForFile(File);
35  if (!Buffer)
36  return SDError::CouldNotLoad;
37 
38  llvm::BitstreamCursor Stream(**Buffer);
40 
41  if (Stream.AtEndOfStream())
43 
44  // Sniff for the signature.
45  if (Stream.Read(8) != 'D' ||
46  Stream.Read(8) != 'I' ||
47  Stream.Read(8) != 'A' ||
48  Stream.Read(8) != 'G')
50 
51  // Read the top level blocks.
52  while (!Stream.AtEndOfStream()) {
53  if (Stream.ReadCode() != llvm::bitc::ENTER_SUBBLOCK)
55 
56  std::error_code EC;
57  switch (Stream.ReadSubBlockID()) {
58  case llvm::bitc::BLOCKINFO_BLOCK_ID:
59  BlockInfo = Stream.ReadBlockInfoBlock();
60  if (!BlockInfo)
62  Stream.setBlockInfo(&*BlockInfo);
63  continue;
64  case BLOCK_META:
65  if ((EC = readMetaBlock(Stream)))
66  return EC;
67  continue;
68  case BLOCK_DIAG:
69  if ((EC = readDiagnosticBlock(Stream)))
70  return EC;
71  continue;
72  default:
73  if (!Stream.SkipBlock())
75  continue;
76  }
77  }
78  return {};
79 }
80 
82  Record = 1,
83  BlockEnd,
84  BlockBegin
85 };
86 
87 llvm::ErrorOr<SerializedDiagnosticReader::Cursor>
88 SerializedDiagnosticReader::skipUntilRecordOrBlock(
89  llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
90  BlockOrRecordID = 0;
91 
92  while (!Stream.AtEndOfStream()) {
93  unsigned Code = Stream.ReadCode();
94 
95  switch ((llvm::bitc::FixedAbbrevIDs)Code) {
96  case llvm::bitc::ENTER_SUBBLOCK:
97  BlockOrRecordID = Stream.ReadSubBlockID();
98  return Cursor::BlockBegin;
99 
100  case llvm::bitc::END_BLOCK:
101  if (Stream.ReadBlockEnd())
103  return Cursor::BlockEnd;
104 
105  case llvm::bitc::DEFINE_ABBREV:
106  Stream.ReadAbbrevRecord();
107  continue;
108 
109  case llvm::bitc::UNABBREV_RECORD:
111 
112  default:
113  // We found a record.
114  BlockOrRecordID = Code;
115  return Cursor::Record;
116  }
117  }
118 
120 }
121 
122 std::error_code
123 SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
124  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META))
126 
127  bool VersionChecked = false;
128 
129  while (true) {
130  unsigned BlockOrCode = 0;
131  llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
132  if (!Res)
133  Res.getError();
134 
135  switch (Res.get()) {
136  case Cursor::Record:
137  break;
138  case Cursor::BlockBegin:
139  if (Stream.SkipBlock())
141  LLVM_FALLTHROUGH;
142  case Cursor::BlockEnd:
143  if (!VersionChecked)
145  return {};
146  }
147 
149  unsigned RecordID = Stream.readRecord(BlockOrCode, Record);
150 
151  if (RecordID == RECORD_VERSION) {
152  if (Record.size() < 1)
154  if (Record[0] > VersionNumber)
156  VersionChecked = true;
157  }
158  }
159 }
160 
161 std::error_code
162 SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
163  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG))
165 
166  std::error_code EC;
167  if ((EC = visitStartOfDiagnostic()))
168  return EC;
169 
171  while (true) {
172  unsigned BlockOrCode = 0;
173  llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
174  if (!Res)
175  Res.getError();
176 
177  switch (Res.get()) {
178  case Cursor::BlockBegin:
179  // The only blocks we care about are subdiagnostics.
180  if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
181  if ((EC = readDiagnosticBlock(Stream)))
182  return EC;
183  } else if (!Stream.SkipBlock())
185  continue;
186  case Cursor::BlockEnd:
187  if ((EC = visitEndOfDiagnostic()))
188  return EC;
189  return {};
190  case Cursor::Record:
191  break;
192  }
193 
194  // Read the record.
195  Record.clear();
196  StringRef Blob;
197  unsigned RecID = Stream.readRecord(BlockOrCode, Record, &Blob);
198 
199  if (RecID < serialized_diags::RECORD_FIRST ||
201  continue;
202 
203  switch ((RecordIDs)RecID) {
204  case RECORD_CATEGORY:
205  // A category has ID and name size.
206  if (Record.size() != 2)
208  if ((EC = visitCategoryRecord(Record[0], Blob)))
209  return EC;
210  continue;
211  case RECORD_DIAG:
212  // A diagnostic has severity, location (4), category, flag, and message
213  // size.
214  if (Record.size() != 8)
216  if ((EC = visitDiagnosticRecord(
217  Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
218  Record[5], Record[6], Blob)))
219  return EC;
220  continue;
221  case RECORD_DIAG_FLAG:
222  // A diagnostic flag has ID and name size.
223  if (Record.size() != 2)
225  if ((EC = visitDiagFlagRecord(Record[0], Blob)))
226  return EC;
227  continue;
228  case RECORD_FILENAME:
229  // A filename has ID, size, timestamp, and name size. The size and
230  // timestamp are legacy fields that are always zero these days.
231  if (Record.size() != 4)
233  if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
234  return EC;
235  continue;
236  case RECORD_FIXIT:
237  // A fixit has two locations (4 each) and message size.
238  if (Record.size() != 9)
240  if ((EC = visitFixitRecord(
241  Location(Record[0], Record[1], Record[2], Record[3]),
242  Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
243  return EC;
244  continue;
245  case RECORD_SOURCE_RANGE:
246  // A source range is two locations (4 each).
247  if (Record.size() != 8)
249  if ((EC = visitSourceRangeRecord(
250  Location(Record[0], Record[1], Record[2], Record[3]),
251  Location(Record[4], Record[5], Record[6], Record[7]))))
252  return EC;
253  continue;
254  case RECORD_VERSION:
255  // A version is just a number.
256  if (Record.size() != 1)
258  if ((EC = visitVersionRecord(Record[0])))
259  return EC;
260  continue;
261  }
262  }
263 }
264 
265 namespace {
266 
267 class SDErrorCategoryType final : public std::error_category {
268  const char *name() const noexcept override {
269  return "clang.serialized_diags";
270  }
271 
272  std::string message(int IE) const override {
273  auto E = static_cast<SDError>(IE);
274  switch (E) {
276  return "Failed to open diagnostics file";
278  return "Invalid diagnostics signature";
280  return "Parse error reading diagnostics";
282  return "Malformed block at top-level of diagnostics";
284  return "Malformed sub-block in a diagnostic";
286  return "Malformed BlockInfo block";
288  return "Malformed Metadata block";
290  return "Malformed Diagnostic block";
292  return "Malformed Diagnostic record";
294  return "No version provided in diagnostics";
296  return "Unsupported diagnostics version";
298  return "Bitcode constructs that are not supported in diagnostics appear";
300  return "Generic error occurred while handling a record";
301  }
302  llvm_unreachable("Unknown error type!");
303  }
304 };
305 
306 } // namespace
307 
308 static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;
309 const std::error_category &clang::serialized_diags::SDErrorCategory() {
310  return *ErrorCategory;
311 }
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:117
Defines the clang::FileManager interface and associated types.
virtual std::error_code visitStartOfDiagnostic()
Visit the start of a diagnostic block.
A generic error for subclass handlers that don&#39;t want or need to define their own error_category...
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&#39;s ID to a Name.
virtual std::error_code visitVersionRecord(unsigned Version)
Visit the version of the set of diagnostics.
Dataflow Directional Tag Classes.
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
Defines the clang::FileSystemOptions interface.
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&#39;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.