brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.5 KiB · aad9e44 Raw
370 lines · cpp
1//===- SerializedDiagnosticReader.cpp - Reads diagnostics -----------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Frontend/SerializedDiagnosticReader.h"10#include "clang/Basic/FileManager.h"11#include "clang/Basic/FileSystemOptions.h"12#include "clang/Frontend/SerializedDiagnostics.h"13#include "llvm/ADT/SmallVector.h"14#include "llvm/Bitstream/BitstreamReader.h"15#include "llvm/Support/Compiler.h"16#include "llvm/Support/ErrorHandling.h"17#include "llvm/Support/ErrorOr.h"18#include "llvm/Support/ManagedStatic.h"19#include <cstdint>20#include <optional>21#include <system_error>22 23using namespace clang;24using namespace serialized_diags;25 26std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {27  // Open the diagnostics file.28  FileSystemOptions FO;29  FileManager FileMgr(FO);30 31  auto Buffer = FileMgr.getBufferForFile(File);32  if (!Buffer)33    return SDError::CouldNotLoad;34 35  llvm::BitstreamCursor Stream(**Buffer);36  std::optional<llvm::BitstreamBlockInfo> BlockInfo;37 38  if (Stream.AtEndOfStream())39    return SDError::InvalidSignature;40 41  // Sniff for the signature.42  for (unsigned char C : {'D', 'I', 'A', 'G'}) {43    if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Stream.Read(8)) {44      if (Res.get() == C)45        continue;46    } else {47      // FIXME this drops the error on the floor.48      consumeError(Res.takeError());49    }50    return SDError::InvalidSignature;51  }52 53  // Read the top level blocks.54  while (!Stream.AtEndOfStream()) {55    if (Expected<unsigned> Res = Stream.ReadCode()) {56      if (Res.get() != llvm::bitc::ENTER_SUBBLOCK)57        return SDError::InvalidDiagnostics;58    } else {59      // FIXME this drops the error on the floor.60      consumeError(Res.takeError());61      return SDError::InvalidDiagnostics;62    }63 64    std::error_code EC;65    Expected<unsigned> MaybeSubBlockID = Stream.ReadSubBlockID();66    if (!MaybeSubBlockID) {67      // FIXME this drops the error on the floor.68      consumeError(MaybeSubBlockID.takeError());69      return SDError::InvalidDiagnostics;70    }71 72    switch (MaybeSubBlockID.get()) {73    case llvm::bitc::BLOCKINFO_BLOCK_ID: {74      Expected<std::optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo =75          Stream.ReadBlockInfoBlock();76      if (!MaybeBlockInfo) {77        // FIXME this drops the error on the floor.78        consumeError(MaybeBlockInfo.takeError());79        return SDError::InvalidDiagnostics;80      }81      BlockInfo = std::move(MaybeBlockInfo.get());82    }83      if (!BlockInfo)84        return SDError::MalformedBlockInfoBlock;85      Stream.setBlockInfo(&*BlockInfo);86      continue;87    case BLOCK_META:88      if ((EC = readMetaBlock(Stream)))89        return EC;90      continue;91    case BLOCK_DIAG:92      if ((EC = readDiagnosticBlock(Stream)))93        return EC;94      continue;95    default:96      if (llvm::Error Err = Stream.SkipBlock()) {97        // FIXME this drops the error on the floor.98        consumeError(std::move(Err));99        return SDError::MalformedTopLevelBlock;100      }101      continue;102    }103  }104  return {};105}106 107enum class SerializedDiagnosticReader::Cursor {108  Record = 1,109  BlockEnd,110  BlockBegin111};112 113llvm::ErrorOr<SerializedDiagnosticReader::Cursor>114SerializedDiagnosticReader::skipUntilRecordOrBlock(115    llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {116  BlockOrRecordID = 0;117 118  while (!Stream.AtEndOfStream()) {119    unsigned Code;120    if (Expected<unsigned> Res = Stream.ReadCode())121      Code = Res.get();122    else123      return llvm::errorToErrorCode(Res.takeError());124 125    if (Code >= static_cast<unsigned>(llvm::bitc::FIRST_APPLICATION_ABBREV)) {126      // We found a record.127      BlockOrRecordID = Code;128      return Cursor::Record;129    }130    switch (static_cast<llvm::bitc::FixedAbbrevIDs>(Code)) {131    case llvm::bitc::ENTER_SUBBLOCK:132      if (Expected<unsigned> Res = Stream.ReadSubBlockID())133        BlockOrRecordID = Res.get();134      else135        return llvm::errorToErrorCode(Res.takeError());136      return Cursor::BlockBegin;137 138    case llvm::bitc::END_BLOCK:139      if (Stream.ReadBlockEnd())140        return SDError::InvalidDiagnostics;141      return Cursor::BlockEnd;142 143    case llvm::bitc::DEFINE_ABBREV:144      if (llvm::Error Err = Stream.ReadAbbrevRecord())145        return llvm::errorToErrorCode(std::move(Err));146      continue;147 148    case llvm::bitc::UNABBREV_RECORD:149      return SDError::UnsupportedConstruct;150 151    case llvm::bitc::FIRST_APPLICATION_ABBREV:152      llvm_unreachable("Unexpected abbrev id.");153    }154  }155 156  return SDError::InvalidDiagnostics;157}158 159std::error_code160SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {161  if (llvm::Error Err =162          Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {163    // FIXME this drops the error on the floor.164    consumeError(std::move(Err));165    return SDError::MalformedMetadataBlock;166  }167 168  bool VersionChecked = false;169 170  while (true) {171    unsigned BlockOrCode = 0;172    llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);173    if (!Res)174      Res.getError();175 176    switch (Res.get()) {177    case Cursor::Record:178      break;179    case Cursor::BlockBegin:180      if (llvm::Error Err = Stream.SkipBlock()) {181        // FIXME this drops the error on the floor.182        consumeError(std::move(Err));183        return SDError::MalformedMetadataBlock;184      }185      [[fallthrough]];186    case Cursor::BlockEnd:187      if (!VersionChecked)188        return SDError::MissingVersion;189      return {};190    }191 192    SmallVector<uint64_t, 1> Record;193    Expected<unsigned> MaybeRecordID = Stream.readRecord(BlockOrCode, Record);194    if (!MaybeRecordID)195      return errorToErrorCode(MaybeRecordID.takeError());196    unsigned RecordID = MaybeRecordID.get();197 198    if (RecordID == RECORD_VERSION) {199      if (Record.size() < 1)200        return SDError::MissingVersion;201      if (Record[0] > VersionNumber)202        return SDError::VersionMismatch;203      VersionChecked = true;204    }205  }206}207 208std::error_code209SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {210  if (llvm::Error Err =211          Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {212    // FIXME this drops the error on the floor.213    consumeError(std::move(Err));214    return SDError::MalformedDiagnosticBlock;215  }216 217  std::error_code EC;218  if ((EC = visitStartOfDiagnostic()))219    return EC;220 221  SmallVector<uint64_t, 16> Record;222  while (true) {223    unsigned BlockOrCode = 0;224    llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);225    if (!Res)226      Res.getError();227 228    switch (Res.get()) {229    case Cursor::BlockBegin:230      // The only blocks we care about are subdiagnostics.231      if (BlockOrCode == serialized_diags::BLOCK_DIAG) {232        if ((EC = readDiagnosticBlock(Stream)))233          return EC;234      } else if (llvm::Error Err = Stream.SkipBlock()) {235        // FIXME this drops the error on the floor.236        consumeError(std::move(Err));237        return SDError::MalformedSubBlock;238      }239      continue;240    case Cursor::BlockEnd:241      if ((EC = visitEndOfDiagnostic()))242        return EC;243      return {};244    case Cursor::Record:245      break;246    }247 248    // Read the record.249    Record.clear();250    StringRef Blob;251    Expected<unsigned> MaybeRecID =252        Stream.readRecord(BlockOrCode, Record, &Blob);253    if (!MaybeRecID)254      return errorToErrorCode(MaybeRecID.takeError());255    unsigned RecID = MaybeRecID.get();256 257    if (RecID < serialized_diags::RECORD_FIRST ||258        RecID > serialized_diags::RECORD_LAST)259      continue;260 261    switch ((RecordIDs)RecID) {262    case RECORD_CATEGORY:263      // A category has ID and name size.264      if (Record.size() != 2)265        return SDError::MalformedDiagnosticRecord;266      if ((EC = visitCategoryRecord(Record[0], Blob)))267        return EC;268      continue;269    case RECORD_DIAG:270      // A diagnostic has severity, location (4), category, flag, and message271      // size.272      if (Record.size() != 8)273        return SDError::MalformedDiagnosticRecord;274      if ((EC = visitDiagnosticRecord(275               Record[0], Location(Record[1], Record[2], Record[3], Record[4]),276               Record[5], Record[6], Blob)))277        return EC;278      continue;279    case RECORD_DIAG_FLAG:280      // A diagnostic flag has ID and name size.281      if (Record.size() != 2)282        return SDError::MalformedDiagnosticRecord;283      if ((EC = visitDiagFlagRecord(Record[0], Blob)))284        return EC;285      continue;286    case RECORD_FILENAME:287      // A filename has ID, size, timestamp, and name size. The size and288      // timestamp are legacy fields that are always zero these days.289      if (Record.size() != 4)290        return SDError::MalformedDiagnosticRecord;291      if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))292        return EC;293      continue;294    case RECORD_FIXIT:295      // A fixit has two locations (4 each) and message size.296      if (Record.size() != 9)297        return SDError::MalformedDiagnosticRecord;298      if ((EC = visitFixitRecord(299               Location(Record[0], Record[1], Record[2], Record[3]),300               Location(Record[4], Record[5], Record[6], Record[7]), Blob)))301        return EC;302      continue;303    case RECORD_SOURCE_RANGE:304      // A source range is two locations (4 each).305      if (Record.size() != 8)306        return SDError::MalformedDiagnosticRecord;307      if ((EC = visitSourceRangeRecord(308               Location(Record[0], Record[1], Record[2], Record[3]),309               Location(Record[4], Record[5], Record[6], Record[7]))))310        return EC;311      continue;312    case RECORD_VERSION:313      // A version is just a number.314      if (Record.size() != 1)315        return SDError::MalformedDiagnosticRecord;316      if ((EC = visitVersionRecord(Record[0])))317        return EC;318      continue;319    }320  }321}322 323namespace {324 325class SDErrorCategoryType final : public std::error_category {326  const char *name() const noexcept override {327    return "clang.serialized_diags";328  }329 330  std::string message(int IE) const override {331    auto E = static_cast<SDError>(IE);332    switch (E) {333    case SDError::CouldNotLoad:334      return "Failed to open diagnostics file";335    case SDError::InvalidSignature:336      return "Invalid diagnostics signature";337    case SDError::InvalidDiagnostics:338      return "Parse error reading diagnostics";339    case SDError::MalformedTopLevelBlock:340      return "Malformed block at top-level of diagnostics";341    case SDError::MalformedSubBlock:342      return "Malformed sub-block in a diagnostic";343    case SDError::MalformedBlockInfoBlock:344      return "Malformed BlockInfo block";345    case SDError::MalformedMetadataBlock:346      return "Malformed Metadata block";347    case SDError::MalformedDiagnosticBlock:348      return "Malformed Diagnostic block";349    case SDError::MalformedDiagnosticRecord:350      return "Malformed Diagnostic record";351    case SDError::MissingVersion:352      return "No version provided in diagnostics";353    case SDError::VersionMismatch:354      return "Unsupported diagnostics version";355    case SDError::UnsupportedConstruct:356      return "Bitcode constructs that are not supported in diagnostics appear";357    case SDError::HandlerFailed:358      return "Generic error occurred while handling a record";359    }360    llvm_unreachable("Unknown error type!");361  }362};363 364} // namespace365 366static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;367const std::error_category &clang::serialized_diags::SDErrorCategory() {368  return *ErrorCategory;369}370