10b57cec5SDimitry Andric //===- YAMLRemarkParser.cpp -----------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file provides utility methods used by clients that want to use the
100b57cec5SDimitry Andric // parser for remark diagnostics in LLVM.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "YAMLRemarkParser.h"
1506c3fb27SDimitry Andric #include "llvm/ADT/SmallString.h"
160b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
178bcb0991SDimitry Andric #include "llvm/Support/Endian.h"
188bcb0991SDimitry Andric #include "llvm/Support/Path.h"
19bdd1243dSDimitry Andric #include <optional>
200b57cec5SDimitry Andric
210b57cec5SDimitry Andric using namespace llvm;
220b57cec5SDimitry Andric using namespace llvm::remarks;
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric char YAMLParseError::ID = 0;
250b57cec5SDimitry Andric
handleDiagnostic(const SMDiagnostic & Diag,void * Ctx)260b57cec5SDimitry Andric static void handleDiagnostic(const SMDiagnostic &Diag, void *Ctx) {
270b57cec5SDimitry Andric assert(Ctx && "Expected non-null Ctx in diagnostic handler.");
280b57cec5SDimitry Andric std::string &Message = *static_cast<std::string *>(Ctx);
290b57cec5SDimitry Andric assert(Message.empty() && "Expected an empty string.");
300b57cec5SDimitry Andric raw_string_ostream OS(Message);
310b57cec5SDimitry Andric Diag.print(/*ProgName=*/nullptr, OS, /*ShowColors*/ false,
320b57cec5SDimitry Andric /*ShowKindLabels*/ true);
330b57cec5SDimitry Andric OS << '\n';
340b57cec5SDimitry Andric OS.flush();
350b57cec5SDimitry Andric }
360b57cec5SDimitry Andric
YAMLParseError(StringRef Msg,SourceMgr & SM,yaml::Stream & Stream,yaml::Node & Node)370b57cec5SDimitry Andric YAMLParseError::YAMLParseError(StringRef Msg, SourceMgr &SM,
380b57cec5SDimitry Andric yaml::Stream &Stream, yaml::Node &Node) {
390b57cec5SDimitry Andric // 1) Set up a diagnostic handler to avoid errors being printed out to
400b57cec5SDimitry Andric // stderr.
410b57cec5SDimitry Andric // 2) Use the stream to print the error with the associated node.
420b57cec5SDimitry Andric // 3) The stream will use the source manager to print the error, which will
430b57cec5SDimitry Andric // call the diagnostic handler.
440b57cec5SDimitry Andric // 4) The diagnostic handler will stream the error directly into this object's
450b57cec5SDimitry Andric // Message member, which is used when logging is asked for.
460b57cec5SDimitry Andric auto OldDiagHandler = SM.getDiagHandler();
470b57cec5SDimitry Andric auto OldDiagCtx = SM.getDiagContext();
480b57cec5SDimitry Andric SM.setDiagHandler(handleDiagnostic, &Message);
490b57cec5SDimitry Andric Stream.printError(&Node, Twine(Msg) + Twine('\n'));
500b57cec5SDimitry Andric // Restore the old handlers.
510b57cec5SDimitry Andric SM.setDiagHandler(OldDiagHandler, OldDiagCtx);
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric
setupSM(std::string & LastErrorMessage)540b57cec5SDimitry Andric static SourceMgr setupSM(std::string &LastErrorMessage) {
550b57cec5SDimitry Andric SourceMgr SM;
560b57cec5SDimitry Andric SM.setDiagHandler(handleDiagnostic, &LastErrorMessage);
570b57cec5SDimitry Andric return SM;
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric
608bcb0991SDimitry Andric // Parse the magic number. This function returns true if this represents remark
618bcb0991SDimitry Andric // metadata, false otherwise.
parseMagic(StringRef & Buf)628bcb0991SDimitry Andric static Expected<bool> parseMagic(StringRef &Buf) {
638bcb0991SDimitry Andric if (!Buf.consume_front(remarks::Magic))
648bcb0991SDimitry Andric return false;
658bcb0991SDimitry Andric
668bcb0991SDimitry Andric if (Buf.size() < 1 || !Buf.consume_front(StringRef("\0", 1)))
678bcb0991SDimitry Andric return createStringError(std::errc::illegal_byte_sequence,
688bcb0991SDimitry Andric "Expecting \\0 after magic number.");
698bcb0991SDimitry Andric return true;
708bcb0991SDimitry Andric }
718bcb0991SDimitry Andric
parseVersion(StringRef & Buf)728bcb0991SDimitry Andric static Expected<uint64_t> parseVersion(StringRef &Buf) {
738bcb0991SDimitry Andric if (Buf.size() < sizeof(uint64_t))
748bcb0991SDimitry Andric return createStringError(std::errc::illegal_byte_sequence,
758bcb0991SDimitry Andric "Expecting version number.");
768bcb0991SDimitry Andric
778bcb0991SDimitry Andric uint64_t Version =
785f757f3fSDimitry Andric support::endian::read<uint64_t, llvm::endianness::little>(Buf.data());
798bcb0991SDimitry Andric if (Version != remarks::CurrentRemarkVersion)
808bcb0991SDimitry Andric return createStringError(std::errc::illegal_byte_sequence,
818bcb0991SDimitry Andric "Mismatching remark version. Got %" PRId64
828bcb0991SDimitry Andric ", expected %" PRId64 ".",
838bcb0991SDimitry Andric Version, remarks::CurrentRemarkVersion);
848bcb0991SDimitry Andric Buf = Buf.drop_front(sizeof(uint64_t));
858bcb0991SDimitry Andric return Version;
868bcb0991SDimitry Andric }
878bcb0991SDimitry Andric
parseStrTabSize(StringRef & Buf)888bcb0991SDimitry Andric static Expected<uint64_t> parseStrTabSize(StringRef &Buf) {
898bcb0991SDimitry Andric if (Buf.size() < sizeof(uint64_t))
908bcb0991SDimitry Andric return createStringError(std::errc::illegal_byte_sequence,
918bcb0991SDimitry Andric "Expecting string table size.");
928bcb0991SDimitry Andric uint64_t StrTabSize =
935f757f3fSDimitry Andric support::endian::read<uint64_t, llvm::endianness::little>(Buf.data());
948bcb0991SDimitry Andric Buf = Buf.drop_front(sizeof(uint64_t));
958bcb0991SDimitry Andric return StrTabSize;
968bcb0991SDimitry Andric }
978bcb0991SDimitry Andric
parseStrTab(StringRef & Buf,uint64_t StrTabSize)988bcb0991SDimitry Andric static Expected<ParsedStringTable> parseStrTab(StringRef &Buf,
998bcb0991SDimitry Andric uint64_t StrTabSize) {
1008bcb0991SDimitry Andric if (Buf.size() < StrTabSize)
1018bcb0991SDimitry Andric return createStringError(std::errc::illegal_byte_sequence,
1028bcb0991SDimitry Andric "Expecting string table.");
1038bcb0991SDimitry Andric
1048bcb0991SDimitry Andric // Attach the string table to the parser.
1058bcb0991SDimitry Andric ParsedStringTable Result(StringRef(Buf.data(), StrTabSize));
1068bcb0991SDimitry Andric Buf = Buf.drop_front(StrTabSize);
1078bcb0991SDimitry Andric return Expected<ParsedStringTable>(std::move(Result));
1088bcb0991SDimitry Andric }
1098bcb0991SDimitry Andric
createYAMLParserFromMeta(StringRef Buf,std::optional<ParsedStringTable> StrTab,std::optional<StringRef> ExternalFilePrependPath)110bdd1243dSDimitry Andric Expected<std::unique_ptr<YAMLRemarkParser>> remarks::createYAMLParserFromMeta(
111bdd1243dSDimitry Andric StringRef Buf, std::optional<ParsedStringTable> StrTab,
112bdd1243dSDimitry Andric std::optional<StringRef> ExternalFilePrependPath) {
1138bcb0991SDimitry Andric // We now have a magic number. The metadata has to be correct.
1148bcb0991SDimitry Andric Expected<bool> isMeta = parseMagic(Buf);
1158bcb0991SDimitry Andric if (!isMeta)
1168bcb0991SDimitry Andric return isMeta.takeError();
1178bcb0991SDimitry Andric // If it's not recognized as metadata, roll back.
1188bcb0991SDimitry Andric std::unique_ptr<MemoryBuffer> SeparateBuf;
1198bcb0991SDimitry Andric if (*isMeta) {
1208bcb0991SDimitry Andric Expected<uint64_t> Version = parseVersion(Buf);
1218bcb0991SDimitry Andric if (!Version)
1228bcb0991SDimitry Andric return Version.takeError();
1238bcb0991SDimitry Andric
1248bcb0991SDimitry Andric Expected<uint64_t> StrTabSize = parseStrTabSize(Buf);
1258bcb0991SDimitry Andric if (!StrTabSize)
1268bcb0991SDimitry Andric return StrTabSize.takeError();
1278bcb0991SDimitry Andric
1288bcb0991SDimitry Andric // If the size of string table is not 0, try to build one.
1298bcb0991SDimitry Andric if (*StrTabSize != 0) {
1308bcb0991SDimitry Andric if (StrTab)
1318bcb0991SDimitry Andric return createStringError(std::errc::illegal_byte_sequence,
1328bcb0991SDimitry Andric "String table already provided.");
1338bcb0991SDimitry Andric Expected<ParsedStringTable> MaybeStrTab = parseStrTab(Buf, *StrTabSize);
1348bcb0991SDimitry Andric if (!MaybeStrTab)
1358bcb0991SDimitry Andric return MaybeStrTab.takeError();
1368bcb0991SDimitry Andric StrTab = std::move(*MaybeStrTab);
1378bcb0991SDimitry Andric }
1388bcb0991SDimitry Andric // If it starts with "---", there is no external file.
1395f757f3fSDimitry Andric if (!Buf.starts_with("---")) {
1408bcb0991SDimitry Andric // At this point, we expect Buf to contain the external file path.
1418bcb0991SDimitry Andric StringRef ExternalFilePath = Buf;
1428bcb0991SDimitry Andric SmallString<80> FullPath;
1438bcb0991SDimitry Andric if (ExternalFilePrependPath)
1448bcb0991SDimitry Andric FullPath = *ExternalFilePrependPath;
1458bcb0991SDimitry Andric sys::path::append(FullPath, ExternalFilePath);
1468bcb0991SDimitry Andric
1478bcb0991SDimitry Andric // Try to open the file and start parsing from there.
1488bcb0991SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
1498bcb0991SDimitry Andric MemoryBuffer::getFile(FullPath);
1508bcb0991SDimitry Andric if (std::error_code EC = BufferOrErr.getError())
1518bcb0991SDimitry Andric return createFileError(FullPath, EC);
1528bcb0991SDimitry Andric
1538bcb0991SDimitry Andric // Keep the buffer alive.
1548bcb0991SDimitry Andric SeparateBuf = std::move(*BufferOrErr);
1558bcb0991SDimitry Andric Buf = SeparateBuf->getBuffer();
1568bcb0991SDimitry Andric }
1578bcb0991SDimitry Andric }
1588bcb0991SDimitry Andric
1598bcb0991SDimitry Andric std::unique_ptr<YAMLRemarkParser> Result =
1608bcb0991SDimitry Andric StrTab
1618bcb0991SDimitry Andric ? std::make_unique<YAMLStrTabRemarkParser>(Buf, std::move(*StrTab))
1628bcb0991SDimitry Andric : std::make_unique<YAMLRemarkParser>(Buf);
1638bcb0991SDimitry Andric if (SeparateBuf)
1648bcb0991SDimitry Andric Result->SeparateBuf = std::move(SeparateBuf);
1658bcb0991SDimitry Andric return std::move(Result);
1668bcb0991SDimitry Andric }
1678bcb0991SDimitry Andric
YAMLRemarkParser(StringRef Buf)1688bcb0991SDimitry Andric YAMLRemarkParser::YAMLRemarkParser(StringRef Buf)
169bdd1243dSDimitry Andric : YAMLRemarkParser(Buf, std::nullopt) {}
1708bcb0991SDimitry Andric
YAMLRemarkParser(StringRef Buf,std::optional<ParsedStringTable> StrTab)1710b57cec5SDimitry Andric YAMLRemarkParser::YAMLRemarkParser(StringRef Buf,
172bdd1243dSDimitry Andric std::optional<ParsedStringTable> StrTab)
17304eeddc0SDimitry Andric : RemarkParser{Format::YAML}, StrTab(std::move(StrTab)),
1740b57cec5SDimitry Andric SM(setupSM(LastErrorMessage)), Stream(Buf, SM), YAMLIt(Stream.begin()) {}
1750b57cec5SDimitry Andric
error(StringRef Message,yaml::Node & Node)1760b57cec5SDimitry Andric Error YAMLRemarkParser::error(StringRef Message, yaml::Node &Node) {
1770b57cec5SDimitry Andric return make_error<YAMLParseError>(Message, SM, Stream, Node);
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric
error()1800b57cec5SDimitry Andric Error YAMLRemarkParser::error() {
1810b57cec5SDimitry Andric if (LastErrorMessage.empty())
1820b57cec5SDimitry Andric return Error::success();
1830b57cec5SDimitry Andric Error E = make_error<YAMLParseError>(LastErrorMessage);
1840b57cec5SDimitry Andric LastErrorMessage.clear();
1850b57cec5SDimitry Andric return E;
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric Expected<std::unique_ptr<Remark>>
parseRemark(yaml::Document & RemarkEntry)1890b57cec5SDimitry Andric YAMLRemarkParser::parseRemark(yaml::Document &RemarkEntry) {
1900b57cec5SDimitry Andric if (Error E = error())
1910b57cec5SDimitry Andric return std::move(E);
1920b57cec5SDimitry Andric
1930b57cec5SDimitry Andric yaml::Node *YAMLRoot = RemarkEntry.getRoot();
1940b57cec5SDimitry Andric if (!YAMLRoot) {
1950b57cec5SDimitry Andric return createStringError(std::make_error_code(std::errc::invalid_argument),
1960b57cec5SDimitry Andric "not a valid YAML file.");
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric
1990b57cec5SDimitry Andric auto *Root = dyn_cast<yaml::MappingNode>(YAMLRoot);
2000b57cec5SDimitry Andric if (!Root)
2010b57cec5SDimitry Andric return error("document root is not of mapping type.", *YAMLRoot);
2020b57cec5SDimitry Andric
2038bcb0991SDimitry Andric std::unique_ptr<Remark> Result = std::make_unique<Remark>();
2040b57cec5SDimitry Andric Remark &TheRemark = *Result;
2050b57cec5SDimitry Andric
2060b57cec5SDimitry Andric // First, the type. It needs special handling since is not part of the
2070b57cec5SDimitry Andric // key-value stream.
2080b57cec5SDimitry Andric Expected<Type> T = parseType(*Root);
2090b57cec5SDimitry Andric if (!T)
2100b57cec5SDimitry Andric return T.takeError();
2110b57cec5SDimitry Andric else
2120b57cec5SDimitry Andric TheRemark.RemarkType = *T;
2130b57cec5SDimitry Andric
2140b57cec5SDimitry Andric // Then, parse the fields, one by one.
2150b57cec5SDimitry Andric for (yaml::KeyValueNode &RemarkField : *Root) {
2160b57cec5SDimitry Andric Expected<StringRef> MaybeKey = parseKey(RemarkField);
2170b57cec5SDimitry Andric if (!MaybeKey)
2180b57cec5SDimitry Andric return MaybeKey.takeError();
2190b57cec5SDimitry Andric StringRef KeyName = *MaybeKey;
2200b57cec5SDimitry Andric
2210b57cec5SDimitry Andric if (KeyName == "Pass") {
2220b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(RemarkField))
2230b57cec5SDimitry Andric TheRemark.PassName = *MaybeStr;
2240b57cec5SDimitry Andric else
2250b57cec5SDimitry Andric return MaybeStr.takeError();
2260b57cec5SDimitry Andric } else if (KeyName == "Name") {
2270b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(RemarkField))
2280b57cec5SDimitry Andric TheRemark.RemarkName = *MaybeStr;
2290b57cec5SDimitry Andric else
2300b57cec5SDimitry Andric return MaybeStr.takeError();
2310b57cec5SDimitry Andric } else if (KeyName == "Function") {
2320b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(RemarkField))
2330b57cec5SDimitry Andric TheRemark.FunctionName = *MaybeStr;
2340b57cec5SDimitry Andric else
2350b57cec5SDimitry Andric return MaybeStr.takeError();
2360b57cec5SDimitry Andric } else if (KeyName == "Hotness") {
2370b57cec5SDimitry Andric if (Expected<unsigned> MaybeU = parseUnsigned(RemarkField))
2380b57cec5SDimitry Andric TheRemark.Hotness = *MaybeU;
2390b57cec5SDimitry Andric else
2400b57cec5SDimitry Andric return MaybeU.takeError();
2410b57cec5SDimitry Andric } else if (KeyName == "DebugLoc") {
2420b57cec5SDimitry Andric if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(RemarkField))
2430b57cec5SDimitry Andric TheRemark.Loc = *MaybeLoc;
2440b57cec5SDimitry Andric else
2450b57cec5SDimitry Andric return MaybeLoc.takeError();
2460b57cec5SDimitry Andric } else if (KeyName == "Args") {
2470b57cec5SDimitry Andric auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue());
2480b57cec5SDimitry Andric if (!Args)
2490b57cec5SDimitry Andric return error("wrong value type for key.", RemarkField);
2500b57cec5SDimitry Andric
2510b57cec5SDimitry Andric for (yaml::Node &Arg : *Args) {
2520b57cec5SDimitry Andric if (Expected<Argument> MaybeArg = parseArg(Arg))
2530b57cec5SDimitry Andric TheRemark.Args.push_back(*MaybeArg);
2540b57cec5SDimitry Andric else
2550b57cec5SDimitry Andric return MaybeArg.takeError();
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric } else {
2580b57cec5SDimitry Andric return error("unknown key.", RemarkField);
2590b57cec5SDimitry Andric }
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric
2620b57cec5SDimitry Andric // Check if any of the mandatory fields are missing.
2630b57cec5SDimitry Andric if (TheRemark.RemarkType == Type::Unknown || TheRemark.PassName.empty() ||
2640b57cec5SDimitry Andric TheRemark.RemarkName.empty() || TheRemark.FunctionName.empty())
2650b57cec5SDimitry Andric return error("Type, Pass, Name or Function missing.",
2660b57cec5SDimitry Andric *RemarkEntry.getRoot());
2670b57cec5SDimitry Andric
2680b57cec5SDimitry Andric return std::move(Result);
2690b57cec5SDimitry Andric }
2700b57cec5SDimitry Andric
parseType(yaml::MappingNode & Node)2710b57cec5SDimitry Andric Expected<Type> YAMLRemarkParser::parseType(yaml::MappingNode &Node) {
2720b57cec5SDimitry Andric auto Type = StringSwitch<remarks::Type>(Node.getRawTag())
2730b57cec5SDimitry Andric .Case("!Passed", remarks::Type::Passed)
2740b57cec5SDimitry Andric .Case("!Missed", remarks::Type::Missed)
2750b57cec5SDimitry Andric .Case("!Analysis", remarks::Type::Analysis)
2760b57cec5SDimitry Andric .Case("!AnalysisFPCommute", remarks::Type::AnalysisFPCommute)
2770b57cec5SDimitry Andric .Case("!AnalysisAliasing", remarks::Type::AnalysisAliasing)
2780b57cec5SDimitry Andric .Case("!Failure", remarks::Type::Failure)
2790b57cec5SDimitry Andric .Default(remarks::Type::Unknown);
2800b57cec5SDimitry Andric if (Type == remarks::Type::Unknown)
2810b57cec5SDimitry Andric return error("expected a remark tag.", Node);
2820b57cec5SDimitry Andric return Type;
2830b57cec5SDimitry Andric }
2840b57cec5SDimitry Andric
parseKey(yaml::KeyValueNode & Node)2850b57cec5SDimitry Andric Expected<StringRef> YAMLRemarkParser::parseKey(yaml::KeyValueNode &Node) {
2860b57cec5SDimitry Andric if (auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey()))
2870b57cec5SDimitry Andric return Key->getRawValue();
2880b57cec5SDimitry Andric
2890b57cec5SDimitry Andric return error("key is not a string.", Node);
2900b57cec5SDimitry Andric }
2910b57cec5SDimitry Andric
parseStr(yaml::KeyValueNode & Node)2920b57cec5SDimitry Andric Expected<StringRef> YAMLRemarkParser::parseStr(yaml::KeyValueNode &Node) {
2930b57cec5SDimitry Andric auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
29406c3fb27SDimitry Andric yaml::BlockScalarNode *ValueBlock;
29506c3fb27SDimitry Andric StringRef Result;
29606c3fb27SDimitry Andric if (!Value) {
29706c3fb27SDimitry Andric // Try to parse the value as a block node.
29806c3fb27SDimitry Andric ValueBlock = dyn_cast<yaml::BlockScalarNode>(Node.getValue());
29906c3fb27SDimitry Andric if (!ValueBlock)
3000b57cec5SDimitry Andric return error("expected a value of scalar type.", Node);
30106c3fb27SDimitry Andric Result = ValueBlock->getValue();
30206c3fb27SDimitry Andric } else
30306c3fb27SDimitry Andric Result = Value->getRawValue();
3040b57cec5SDimitry Andric
305*7a6dacacSDimitry Andric Result.consume_front("\'");
306*7a6dacacSDimitry Andric Result.consume_back("\'");
3070b57cec5SDimitry Andric
3080b57cec5SDimitry Andric return Result;
3090b57cec5SDimitry Andric }
3100b57cec5SDimitry Andric
parseUnsigned(yaml::KeyValueNode & Node)3110b57cec5SDimitry Andric Expected<unsigned> YAMLRemarkParser::parseUnsigned(yaml::KeyValueNode &Node) {
3120b57cec5SDimitry Andric SmallVector<char, 4> Tmp;
3130b57cec5SDimitry Andric auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
3140b57cec5SDimitry Andric if (!Value)
3150b57cec5SDimitry Andric return error("expected a value of scalar type.", Node);
3160b57cec5SDimitry Andric unsigned UnsignedValue = 0;
3170b57cec5SDimitry Andric if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue))
3180b57cec5SDimitry Andric return error("expected a value of integer type.", *Value);
3190b57cec5SDimitry Andric return UnsignedValue;
3200b57cec5SDimitry Andric }
3210b57cec5SDimitry Andric
3220b57cec5SDimitry Andric Expected<RemarkLocation>
parseDebugLoc(yaml::KeyValueNode & Node)3230b57cec5SDimitry Andric YAMLRemarkParser::parseDebugLoc(yaml::KeyValueNode &Node) {
3240b57cec5SDimitry Andric auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue());
3250b57cec5SDimitry Andric if (!DebugLoc)
3260b57cec5SDimitry Andric return error("expected a value of mapping type.", Node);
3270b57cec5SDimitry Andric
328bdd1243dSDimitry Andric std::optional<StringRef> File;
329bdd1243dSDimitry Andric std::optional<unsigned> Line;
330bdd1243dSDimitry Andric std::optional<unsigned> Column;
3310b57cec5SDimitry Andric
3320b57cec5SDimitry Andric for (yaml::KeyValueNode &DLNode : *DebugLoc) {
3330b57cec5SDimitry Andric Expected<StringRef> MaybeKey = parseKey(DLNode);
3340b57cec5SDimitry Andric if (!MaybeKey)
3350b57cec5SDimitry Andric return MaybeKey.takeError();
3360b57cec5SDimitry Andric StringRef KeyName = *MaybeKey;
3370b57cec5SDimitry Andric
3380b57cec5SDimitry Andric if (KeyName == "File") {
3390b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(DLNode))
3400b57cec5SDimitry Andric File = *MaybeStr;
3410b57cec5SDimitry Andric else
3420b57cec5SDimitry Andric return MaybeStr.takeError();
3430b57cec5SDimitry Andric } else if (KeyName == "Column") {
3440b57cec5SDimitry Andric if (Expected<unsigned> MaybeU = parseUnsigned(DLNode))
3450b57cec5SDimitry Andric Column = *MaybeU;
3460b57cec5SDimitry Andric else
3470b57cec5SDimitry Andric return MaybeU.takeError();
3480b57cec5SDimitry Andric } else if (KeyName == "Line") {
3490b57cec5SDimitry Andric if (Expected<unsigned> MaybeU = parseUnsigned(DLNode))
3500b57cec5SDimitry Andric Line = *MaybeU;
3510b57cec5SDimitry Andric else
3520b57cec5SDimitry Andric return MaybeU.takeError();
3530b57cec5SDimitry Andric } else {
3540b57cec5SDimitry Andric return error("unknown entry in DebugLoc map.", DLNode);
3550b57cec5SDimitry Andric }
3560b57cec5SDimitry Andric }
3570b57cec5SDimitry Andric
3580b57cec5SDimitry Andric // If any of the debug loc fields is missing, return an error.
3590b57cec5SDimitry Andric if (!File || !Line || !Column)
3600b57cec5SDimitry Andric return error("DebugLoc node incomplete.", Node);
3610b57cec5SDimitry Andric
3620b57cec5SDimitry Andric return RemarkLocation{*File, *Line, *Column};
3630b57cec5SDimitry Andric }
3640b57cec5SDimitry Andric
parseArg(yaml::Node & Node)3650b57cec5SDimitry Andric Expected<Argument> YAMLRemarkParser::parseArg(yaml::Node &Node) {
3660b57cec5SDimitry Andric auto *ArgMap = dyn_cast<yaml::MappingNode>(&Node);
3670b57cec5SDimitry Andric if (!ArgMap)
3680b57cec5SDimitry Andric return error("expected a value of mapping type.", Node);
3690b57cec5SDimitry Andric
370bdd1243dSDimitry Andric std::optional<StringRef> KeyStr;
371bdd1243dSDimitry Andric std::optional<StringRef> ValueStr;
372bdd1243dSDimitry Andric std::optional<RemarkLocation> Loc;
3730b57cec5SDimitry Andric
3740b57cec5SDimitry Andric for (yaml::KeyValueNode &ArgEntry : *ArgMap) {
3750b57cec5SDimitry Andric Expected<StringRef> MaybeKey = parseKey(ArgEntry);
3760b57cec5SDimitry Andric if (!MaybeKey)
3770b57cec5SDimitry Andric return MaybeKey.takeError();
3780b57cec5SDimitry Andric StringRef KeyName = *MaybeKey;
3790b57cec5SDimitry Andric
3800b57cec5SDimitry Andric // Try to parse debug locs.
3810b57cec5SDimitry Andric if (KeyName == "DebugLoc") {
3820b57cec5SDimitry Andric // Can't have multiple DebugLoc entries per argument.
3830b57cec5SDimitry Andric if (Loc)
3840b57cec5SDimitry Andric return error("only one DebugLoc entry is allowed per argument.",
3850b57cec5SDimitry Andric ArgEntry);
3860b57cec5SDimitry Andric
3870b57cec5SDimitry Andric if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(ArgEntry)) {
3880b57cec5SDimitry Andric Loc = *MaybeLoc;
3890b57cec5SDimitry Andric continue;
3900b57cec5SDimitry Andric } else
3910b57cec5SDimitry Andric return MaybeLoc.takeError();
3920b57cec5SDimitry Andric }
3930b57cec5SDimitry Andric
3940b57cec5SDimitry Andric // If we already have a string, error out.
3950b57cec5SDimitry Andric if (ValueStr)
3960b57cec5SDimitry Andric return error("only one string entry is allowed per argument.", ArgEntry);
3970b57cec5SDimitry Andric
3980b57cec5SDimitry Andric // Try to parse the value.
3990b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(ArgEntry))
4000b57cec5SDimitry Andric ValueStr = *MaybeStr;
4010b57cec5SDimitry Andric else
4020b57cec5SDimitry Andric return MaybeStr.takeError();
4030b57cec5SDimitry Andric
4040b57cec5SDimitry Andric // Keep the key from the string.
4050b57cec5SDimitry Andric KeyStr = KeyName;
4060b57cec5SDimitry Andric }
4070b57cec5SDimitry Andric
4080b57cec5SDimitry Andric if (!KeyStr)
4090b57cec5SDimitry Andric return error("argument key is missing.", *ArgMap);
4100b57cec5SDimitry Andric if (!ValueStr)
4110b57cec5SDimitry Andric return error("argument value is missing.", *ArgMap);
4120b57cec5SDimitry Andric
4130b57cec5SDimitry Andric return Argument{*KeyStr, *ValueStr, Loc};
4140b57cec5SDimitry Andric }
4150b57cec5SDimitry Andric
next()4160b57cec5SDimitry Andric Expected<std::unique_ptr<Remark>> YAMLRemarkParser::next() {
4170b57cec5SDimitry Andric if (YAMLIt == Stream.end())
4180b57cec5SDimitry Andric return make_error<EndOfFileError>();
4190b57cec5SDimitry Andric
4200b57cec5SDimitry Andric Expected<std::unique_ptr<Remark>> MaybeResult = parseRemark(*YAMLIt);
4210b57cec5SDimitry Andric if (!MaybeResult) {
4220b57cec5SDimitry Andric // Avoid garbage input, set the iterator to the end.
4230b57cec5SDimitry Andric YAMLIt = Stream.end();
4240b57cec5SDimitry Andric return MaybeResult.takeError();
4250b57cec5SDimitry Andric }
4260b57cec5SDimitry Andric
4270b57cec5SDimitry Andric ++YAMLIt;
4280b57cec5SDimitry Andric
4290b57cec5SDimitry Andric return std::move(*MaybeResult);
4300b57cec5SDimitry Andric }
4318bcb0991SDimitry Andric
parseStr(yaml::KeyValueNode & Node)4328bcb0991SDimitry Andric Expected<StringRef> YAMLStrTabRemarkParser::parseStr(yaml::KeyValueNode &Node) {
4338bcb0991SDimitry Andric auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
43406c3fb27SDimitry Andric yaml::BlockScalarNode *ValueBlock;
4358bcb0991SDimitry Andric StringRef Result;
43606c3fb27SDimitry Andric if (!Value) {
43706c3fb27SDimitry Andric // Try to parse the value as a block node.
43806c3fb27SDimitry Andric ValueBlock = dyn_cast<yaml::BlockScalarNode>(Node.getValue());
43906c3fb27SDimitry Andric if (!ValueBlock)
44006c3fb27SDimitry Andric return error("expected a value of scalar type.", Node);
44106c3fb27SDimitry Andric Result = ValueBlock->getValue();
44206c3fb27SDimitry Andric } else
44306c3fb27SDimitry Andric Result = Value->getRawValue();
4448bcb0991SDimitry Andric // If we have a string table, parse it as an unsigned.
4458bcb0991SDimitry Andric unsigned StrID = 0;
4468bcb0991SDimitry Andric if (Expected<unsigned> MaybeStrID = parseUnsigned(Node))
4478bcb0991SDimitry Andric StrID = *MaybeStrID;
4488bcb0991SDimitry Andric else
4498bcb0991SDimitry Andric return MaybeStrID.takeError();
4508bcb0991SDimitry Andric
4518bcb0991SDimitry Andric if (Expected<StringRef> Str = (*StrTab)[StrID])
4528bcb0991SDimitry Andric Result = *Str;
4538bcb0991SDimitry Andric else
4548bcb0991SDimitry Andric return Str.takeError();
4558bcb0991SDimitry Andric
456*7a6dacacSDimitry Andric Result.consume_front("\'");
457*7a6dacacSDimitry Andric Result.consume_back("\'");
4588bcb0991SDimitry Andric
4598bcb0991SDimitry Andric return Result;
4608bcb0991SDimitry Andric }
461