clang  6.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 
13 #include "llvm/Support/ManagedStatic.h"
14 
15 using namespace clang;
16 using namespace clang::serialized_diags;
17 
18 std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
19  // Open the diagnostics file.
21  FileManager FileMgr(FO);
22 
23  auto Buffer = FileMgr.getBufferForFile(File);
24  if (!Buffer)
25  return SDError::CouldNotLoad;
26 
27  llvm::BitstreamCursor Stream(**Buffer);
29 
30  if (Stream.AtEndOfStream())
32 
33  // Sniff for the signature.
34  if (Stream.Read(8) != 'D' ||
35  Stream.Read(8) != 'I' ||
36  Stream.Read(8) != 'A' ||
37  Stream.Read(8) != 'G')
39 
40  // Read the top level blocks.
41  while (!Stream.AtEndOfStream()) {
42  if (Stream.ReadCode() != llvm::bitc::ENTER_SUBBLOCK)
44 
45  std::error_code EC;
46  switch (Stream.ReadSubBlockID()) {
47  case llvm::bitc::BLOCKINFO_BLOCK_ID: {
48  BlockInfo = Stream.ReadBlockInfoBlock();
49  if (!BlockInfo)
51  Stream.setBlockInfo(&*BlockInfo);
52  continue;
53  }
54  case BLOCK_META:
55  if ((EC = readMetaBlock(Stream)))
56  return EC;
57  continue;
58  case BLOCK_DIAG:
59  if ((EC = readDiagnosticBlock(Stream)))
60  return EC;
61  continue;
62  default:
63  if (!Stream.SkipBlock())
65  continue;
66  }
67  }
68  return std::error_code();
69 }
70 
72  Record = 1,
73  BlockEnd,
74  BlockBegin
75 };
76 
77 llvm::ErrorOr<SerializedDiagnosticReader::Cursor>
78 SerializedDiagnosticReader::skipUntilRecordOrBlock(
79  llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
80  BlockOrRecordID = 0;
81 
82  while (!Stream.AtEndOfStream()) {
83  unsigned Code = Stream.ReadCode();
84 
85  switch ((llvm::bitc::FixedAbbrevIDs)Code) {
86  case llvm::bitc::ENTER_SUBBLOCK:
87  BlockOrRecordID = Stream.ReadSubBlockID();
88  return Cursor::BlockBegin;
89 
90  case llvm::bitc::END_BLOCK:
91  if (Stream.ReadBlockEnd())
93  return Cursor::BlockEnd;
94 
95  case llvm::bitc::DEFINE_ABBREV:
96  Stream.ReadAbbrevRecord();
97  continue;
98 
99  case llvm::bitc::UNABBREV_RECORD:
101 
102  default:
103  // We found a record.
104  BlockOrRecordID = Code;
105  return Cursor::Record;
106  }
107  }
108 
110 }
111 
112 std::error_code
113 SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
114  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META))
116 
117  bool VersionChecked = false;
118 
119  while (true) {
120  unsigned BlockOrCode = 0;
121  llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
122  if (!Res)
123  Res.getError();
124 
125  switch (Res.get()) {
126  case Cursor::Record:
127  break;
128  case Cursor::BlockBegin:
129  if (Stream.SkipBlock())
131  LLVM_FALLTHROUGH;
132  case Cursor::BlockEnd:
133  if (!VersionChecked)
135  return std::error_code();
136  }
137 
139  unsigned RecordID = Stream.readRecord(BlockOrCode, Record);
140 
141  if (RecordID == RECORD_VERSION) {
142  if (Record.size() < 1)
144  if (Record[0] > VersionNumber)
146  VersionChecked = true;
147  }
148  }
149 }
150 
151 std::error_code
152 SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
153  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG))
155 
156  std::error_code EC;
157  if ((EC = visitStartOfDiagnostic()))
158  return EC;
159 
161  while (true) {
162  unsigned BlockOrCode = 0;
163  llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
164  if (!Res)
165  Res.getError();
166 
167  switch (Res.get()) {
168  case Cursor::BlockBegin:
169  // The only blocks we care about are subdiagnostics.
170  if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
171  if ((EC = readDiagnosticBlock(Stream)))
172  return EC;
173  } else if (!Stream.SkipBlock())
175  continue;
176  case Cursor::BlockEnd:
177  if ((EC = visitEndOfDiagnostic()))
178  return EC;
179  return std::error_code();
180  case Cursor::Record:
181  break;
182  }
183 
184  // Read the record.
185  Record.clear();
186  StringRef Blob;
187  unsigned RecID = Stream.readRecord(BlockOrCode, Record, &Blob);
188 
189  if (RecID < serialized_diags::RECORD_FIRST ||
191  continue;
192 
193  switch ((RecordIDs)RecID) {
194  case RECORD_CATEGORY:
195  // A category has ID and name size.
196  if (Record.size() != 2)
198  if ((EC = visitCategoryRecord(Record[0], Blob)))
199  return EC;
200  continue;
201  case RECORD_DIAG:
202  // A diagnostic has severity, location (4), category, flag, and message
203  // size.
204  if (Record.size() != 8)
206  if ((EC = visitDiagnosticRecord(
207  Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
208  Record[5], Record[6], Blob)))
209  return EC;
210  continue;
211  case RECORD_DIAG_FLAG:
212  // A diagnostic flag has ID and name size.
213  if (Record.size() != 2)
215  if ((EC = visitDiagFlagRecord(Record[0], Blob)))
216  return EC;
217  continue;
218  case RECORD_FILENAME:
219  // A filename has ID, size, timestamp, and name size. The size and
220  // timestamp are legacy fields that are always zero these days.
221  if (Record.size() != 4)
223  if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
224  return EC;
225  continue;
226  case RECORD_FIXIT:
227  // A fixit has two locations (4 each) and message size.
228  if (Record.size() != 9)
230  if ((EC = visitFixitRecord(
231  Location(Record[0], Record[1], Record[2], Record[3]),
232  Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
233  return EC;
234  continue;
235  case RECORD_SOURCE_RANGE:
236  // A source range is two locations (4 each).
237  if (Record.size() != 8)
239  if ((EC = visitSourceRangeRecord(
240  Location(Record[0], Record[1], Record[2], Record[3]),
241  Location(Record[4], Record[5], Record[6], Record[7]))))
242  return EC;
243  continue;
244  case RECORD_VERSION:
245  // A version is just a number.
246  if (Record.size() != 1)
248  if ((EC = visitVersionRecord(Record[0])))
249  return EC;
250  continue;
251  }
252  }
253 }
254 
255 namespace {
256 class SDErrorCategoryType final : public std::error_category {
257  const char *name() const noexcept override {
258  return "clang.serialized_diags";
259  }
260  std::string message(int IE) const override {
261  SDError E = static_cast<SDError>(IE);
262  switch (E) {
264  return "Failed to open diagnostics file";
266  return "Invalid diagnostics signature";
268  return "Parse error reading diagnostics";
270  return "Malformed block at top-level of diagnostics";
272  return "Malformed sub-block in a diagnostic";
274  return "Malformed BlockInfo block";
276  return "Malformed Metadata block";
278  return "Malformed Diagnostic block";
280  return "Malformed Diagnostic record";
282  return "No version provided in diagnostics";
284  return "Unsupported diagnostics version";
286  return "Bitcode constructs that are not supported in diagnostics appear";
288  return "Generic error occurred while handling a record";
289  }
290  llvm_unreachable("Unknown error type!");
291  }
292 };
293 }
294 
295 static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;
296 const std::error_category &clang::serialized_diags::SDErrorCategory() {
297  return *ErrorCategory;
298 }
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:116
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
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.