155 lines · cpp
1//===- RemarkParser.cpp --------------------------------------------------===//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// This file provides utility methods used by clients that want to use the10// parser for remark diagnostics in LLVM.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/Remarks/RemarkParser.h"15#include "BitstreamRemarkParser.h"16#include "YAMLRemarkParser.h"17#include "llvm-c/Remarks.h"18#include "llvm/Remarks/RemarkFormat.h"19#include "llvm/Support/CBindingWrapping.h"20#include <optional>21 22using namespace llvm;23using namespace llvm::remarks;24 25char EndOfFileError::ID = 0;26 27ParsedStringTable::ParsedStringTable(StringRef InBuffer) : Buffer(InBuffer) {28 while (!InBuffer.empty()) {29 // Strings are separated by '\0' bytes.30 std::pair<StringRef, StringRef> Split = InBuffer.split('\0');31 // We only store the offset from the beginning of the buffer.32 Offsets.push_back(Split.first.data() - Buffer.data());33 InBuffer = Split.second;34 }35}36 37Expected<StringRef> ParsedStringTable::operator[](size_t Index) const {38 if (Index >= Offsets.size())39 return createStringError(40 std::make_error_code(std::errc::invalid_argument),41 "String with index %u is out of bounds (size = %u).", Index,42 Offsets.size());43 44 size_t Offset = Offsets[Index];45 // If it's the last offset, we can't use the next offset to know the size of46 // the string.47 size_t NextOffset =48 (Index == Offsets.size() - 1) ? Buffer.size() : Offsets[Index + 1];49 return StringRef(Buffer.data() + Offset, NextOffset - Offset - 1);50}51 52Expected<std::unique_ptr<RemarkParser>>53llvm::remarks::createRemarkParser(Format ParserFormat, StringRef Buf) {54 auto DetectedFormat = detectFormat(ParserFormat, Buf);55 if (!DetectedFormat)56 return DetectedFormat.takeError();57 58 switch (*DetectedFormat) {59 case Format::YAML:60 return std::make_unique<YAMLRemarkParser>(Buf);61 case Format::Bitstream:62 return std::make_unique<BitstreamRemarkParser>(Buf);63 case Format::Unknown:64 case Format::Auto:65 break;66 }67 llvm_unreachable("unhandled ParseFormat");68}69 70Expected<std::unique_ptr<RemarkParser>>71llvm::remarks::createRemarkParserFromMeta(72 Format ParserFormat, StringRef Buf,73 std::optional<StringRef> ExternalFilePrependPath) {74 auto DetectedFormat = detectFormat(ParserFormat, Buf);75 if (!DetectedFormat)76 return DetectedFormat.takeError();77 78 switch (*DetectedFormat) {79 case Format::YAML:80 return createYAMLParserFromMeta(Buf, std::move(ExternalFilePrependPath));81 case Format::Bitstream:82 return createBitstreamParserFromMeta(Buf,83 std::move(ExternalFilePrependPath));84 case Format::Unknown:85 case Format::Auto:86 break;87 }88 llvm_unreachable("unhandled ParseFormat");89}90 91namespace {92// Wrapper that holds the state needed to interact with the C API.93struct CParser {94 std::unique_ptr<RemarkParser> TheParser;95 std::optional<std::string> Err;96 97 CParser(Format ParserFormat, StringRef Buf)98 : TheParser(cantFail(createRemarkParser(ParserFormat, Buf))) {}99 100 void handleError(Error E) { Err.emplace(toString(std::move(E))); }101 bool hasError() const { return Err.has_value(); }102 const char *getMessage() const { return Err ? Err->c_str() : nullptr; };103};104} // namespace105 106// Create wrappers for C Binding types (see CBindingWrapping.h).107DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser, LLVMRemarkParserRef)108 109extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf,110 uint64_t Size) {111 return wrap(new CParser(Format::YAML,112 StringRef(static_cast<const char *>(Buf), Size)));113}114 115extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateBitstream(const void *Buf,116 uint64_t Size) {117 return wrap(new CParser(Format::Bitstream,118 StringRef(static_cast<const char *>(Buf), Size)));119}120 121extern "C" LLVMRemarkEntryRef122LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) {123 CParser &TheCParser = *unwrap(Parser);124 remarks::RemarkParser &TheParser = *TheCParser.TheParser;125 126 Expected<std::unique_ptr<Remark>> MaybeRemark = TheParser.next();127 if (Error E = MaybeRemark.takeError()) {128 if (E.isA<EndOfFileError>()) {129 consumeError(std::move(E));130 return nullptr;131 }132 133 // Handle the error. Allow it to be checked through HasError and134 // GetErrorMessage.135 TheCParser.handleError(std::move(E));136 return nullptr;137 }138 139 // Valid remark.140 return wrap(MaybeRemark->release());141}142 143extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) {144 return unwrap(Parser)->hasError();145}146 147extern "C" const char *148LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) {149 return unwrap(Parser)->getMessage();150}151 152extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) {153 delete unwrap(Parser);154}155