xref: /freebsd/contrib/llvm-project/llvm/lib/Remarks/YAMLRemarkParser.cpp (revision 8bcb0991864975618c09697b1aca10683346d9f0)
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"
150b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
160b57cec5SDimitry Andric #include "llvm/Remarks/RemarkParser.h"
17*8bcb0991SDimitry Andric #include "llvm/Support/Endian.h"
18*8bcb0991SDimitry Andric #include "llvm/Support/Path.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric using namespace llvm::remarks;
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric char YAMLParseError::ID = 0;
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric static void handleDiagnostic(const SMDiagnostic &Diag, void *Ctx) {
260b57cec5SDimitry Andric   assert(Ctx && "Expected non-null Ctx in diagnostic handler.");
270b57cec5SDimitry Andric   std::string &Message = *static_cast<std::string *>(Ctx);
280b57cec5SDimitry Andric   assert(Message.empty() && "Expected an empty string.");
290b57cec5SDimitry Andric   raw_string_ostream OS(Message);
300b57cec5SDimitry Andric   Diag.print(/*ProgName=*/nullptr, OS, /*ShowColors*/ false,
310b57cec5SDimitry Andric              /*ShowKindLabels*/ true);
320b57cec5SDimitry Andric   OS << '\n';
330b57cec5SDimitry Andric   OS.flush();
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric YAMLParseError::YAMLParseError(StringRef Msg, SourceMgr &SM,
370b57cec5SDimitry Andric                                yaml::Stream &Stream, yaml::Node &Node) {
380b57cec5SDimitry Andric   // 1) Set up a diagnostic handler to avoid errors being printed out to
390b57cec5SDimitry Andric   // stderr.
400b57cec5SDimitry Andric   // 2) Use the stream to print the error with the associated node.
410b57cec5SDimitry Andric   // 3) The stream will use the source manager to print the error, which will
420b57cec5SDimitry Andric   // call the diagnostic handler.
430b57cec5SDimitry Andric   // 4) The diagnostic handler will stream the error directly into this object's
440b57cec5SDimitry Andric   // Message member, which is used when logging is asked for.
450b57cec5SDimitry Andric   auto OldDiagHandler = SM.getDiagHandler();
460b57cec5SDimitry Andric   auto OldDiagCtx = SM.getDiagContext();
470b57cec5SDimitry Andric   SM.setDiagHandler(handleDiagnostic, &Message);
480b57cec5SDimitry Andric   Stream.printError(&Node, Twine(Msg) + Twine('\n'));
490b57cec5SDimitry Andric   // Restore the old handlers.
500b57cec5SDimitry Andric   SM.setDiagHandler(OldDiagHandler, OldDiagCtx);
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric static SourceMgr setupSM(std::string &LastErrorMessage) {
540b57cec5SDimitry Andric   SourceMgr SM;
550b57cec5SDimitry Andric   SM.setDiagHandler(handleDiagnostic, &LastErrorMessage);
560b57cec5SDimitry Andric   return SM;
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric 
59*8bcb0991SDimitry Andric // Parse the magic number. This function returns true if this represents remark
60*8bcb0991SDimitry Andric // metadata, false otherwise.
61*8bcb0991SDimitry Andric static Expected<bool> parseMagic(StringRef &Buf) {
62*8bcb0991SDimitry Andric   if (!Buf.consume_front(remarks::Magic))
63*8bcb0991SDimitry Andric     return false;
64*8bcb0991SDimitry Andric 
65*8bcb0991SDimitry Andric   if (Buf.size() < 1 || !Buf.consume_front(StringRef("\0", 1)))
66*8bcb0991SDimitry Andric     return createStringError(std::errc::illegal_byte_sequence,
67*8bcb0991SDimitry Andric                              "Expecting \\0 after magic number.");
68*8bcb0991SDimitry Andric   return true;
69*8bcb0991SDimitry Andric }
70*8bcb0991SDimitry Andric 
71*8bcb0991SDimitry Andric static Expected<uint64_t> parseVersion(StringRef &Buf) {
72*8bcb0991SDimitry Andric   if (Buf.size() < sizeof(uint64_t))
73*8bcb0991SDimitry Andric     return createStringError(std::errc::illegal_byte_sequence,
74*8bcb0991SDimitry Andric                              "Expecting version number.");
75*8bcb0991SDimitry Andric 
76*8bcb0991SDimitry Andric   uint64_t Version =
77*8bcb0991SDimitry Andric       support::endian::read<uint64_t, support::little, support::unaligned>(
78*8bcb0991SDimitry Andric           Buf.data());
79*8bcb0991SDimitry Andric   if (Version != remarks::CurrentRemarkVersion)
80*8bcb0991SDimitry Andric     return createStringError(std::errc::illegal_byte_sequence,
81*8bcb0991SDimitry Andric                              "Mismatching remark version. Got %" PRId64
82*8bcb0991SDimitry Andric                              ", expected %" PRId64 ".",
83*8bcb0991SDimitry Andric                              Version, remarks::CurrentRemarkVersion);
84*8bcb0991SDimitry Andric   Buf = Buf.drop_front(sizeof(uint64_t));
85*8bcb0991SDimitry Andric   return Version;
86*8bcb0991SDimitry Andric }
87*8bcb0991SDimitry Andric 
88*8bcb0991SDimitry Andric static Expected<uint64_t> parseStrTabSize(StringRef &Buf) {
89*8bcb0991SDimitry Andric   if (Buf.size() < sizeof(uint64_t))
90*8bcb0991SDimitry Andric     return createStringError(std::errc::illegal_byte_sequence,
91*8bcb0991SDimitry Andric                              "Expecting string table size.");
92*8bcb0991SDimitry Andric   uint64_t StrTabSize =
93*8bcb0991SDimitry Andric       support::endian::read<uint64_t, support::little, support::unaligned>(
94*8bcb0991SDimitry Andric           Buf.data());
95*8bcb0991SDimitry Andric   Buf = Buf.drop_front(sizeof(uint64_t));
96*8bcb0991SDimitry Andric   return StrTabSize;
97*8bcb0991SDimitry Andric }
98*8bcb0991SDimitry Andric 
99*8bcb0991SDimitry Andric static Expected<ParsedStringTable> parseStrTab(StringRef &Buf,
100*8bcb0991SDimitry Andric                                                uint64_t StrTabSize) {
101*8bcb0991SDimitry Andric   if (Buf.size() < StrTabSize)
102*8bcb0991SDimitry Andric     return createStringError(std::errc::illegal_byte_sequence,
103*8bcb0991SDimitry Andric                              "Expecting string table.");
104*8bcb0991SDimitry Andric 
105*8bcb0991SDimitry Andric   // Attach the string table to the parser.
106*8bcb0991SDimitry Andric   ParsedStringTable Result(StringRef(Buf.data(), StrTabSize));
107*8bcb0991SDimitry Andric   Buf = Buf.drop_front(StrTabSize);
108*8bcb0991SDimitry Andric   return Expected<ParsedStringTable>(std::move(Result));
109*8bcb0991SDimitry Andric }
110*8bcb0991SDimitry Andric 
111*8bcb0991SDimitry Andric Expected<std::unique_ptr<YAMLRemarkParser>>
112*8bcb0991SDimitry Andric remarks::createYAMLParserFromMeta(StringRef Buf,
113*8bcb0991SDimitry Andric                                   Optional<ParsedStringTable> StrTab,
114*8bcb0991SDimitry Andric                                   Optional<StringRef> ExternalFilePrependPath) {
115*8bcb0991SDimitry Andric   // We now have a magic number. The metadata has to be correct.
116*8bcb0991SDimitry Andric   Expected<bool> isMeta = parseMagic(Buf);
117*8bcb0991SDimitry Andric   if (!isMeta)
118*8bcb0991SDimitry Andric     return isMeta.takeError();
119*8bcb0991SDimitry Andric   // If it's not recognized as metadata, roll back.
120*8bcb0991SDimitry Andric   std::unique_ptr<MemoryBuffer> SeparateBuf;
121*8bcb0991SDimitry Andric   if (*isMeta) {
122*8bcb0991SDimitry Andric     Expected<uint64_t> Version = parseVersion(Buf);
123*8bcb0991SDimitry Andric     if (!Version)
124*8bcb0991SDimitry Andric       return Version.takeError();
125*8bcb0991SDimitry Andric 
126*8bcb0991SDimitry Andric     Expected<uint64_t> StrTabSize = parseStrTabSize(Buf);
127*8bcb0991SDimitry Andric     if (!StrTabSize)
128*8bcb0991SDimitry Andric       return StrTabSize.takeError();
129*8bcb0991SDimitry Andric 
130*8bcb0991SDimitry Andric     // If the size of string table is not 0, try to build one.
131*8bcb0991SDimitry Andric     if (*StrTabSize != 0) {
132*8bcb0991SDimitry Andric       if (StrTab)
133*8bcb0991SDimitry Andric         return createStringError(std::errc::illegal_byte_sequence,
134*8bcb0991SDimitry Andric                                  "String table already provided.");
135*8bcb0991SDimitry Andric       Expected<ParsedStringTable> MaybeStrTab = parseStrTab(Buf, *StrTabSize);
136*8bcb0991SDimitry Andric       if (!MaybeStrTab)
137*8bcb0991SDimitry Andric         return MaybeStrTab.takeError();
138*8bcb0991SDimitry Andric       StrTab = std::move(*MaybeStrTab);
139*8bcb0991SDimitry Andric     }
140*8bcb0991SDimitry Andric     // If it starts with "---", there is no external file.
141*8bcb0991SDimitry Andric     if (!Buf.startswith("---")) {
142*8bcb0991SDimitry Andric       // At this point, we expect Buf to contain the external file path.
143*8bcb0991SDimitry Andric       StringRef ExternalFilePath = Buf;
144*8bcb0991SDimitry Andric       SmallString<80> FullPath;
145*8bcb0991SDimitry Andric       if (ExternalFilePrependPath)
146*8bcb0991SDimitry Andric         FullPath = *ExternalFilePrependPath;
147*8bcb0991SDimitry Andric       sys::path::append(FullPath, ExternalFilePath);
148*8bcb0991SDimitry Andric 
149*8bcb0991SDimitry Andric       // Try to open the file and start parsing from there.
150*8bcb0991SDimitry Andric       ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
151*8bcb0991SDimitry Andric           MemoryBuffer::getFile(FullPath);
152*8bcb0991SDimitry Andric       if (std::error_code EC = BufferOrErr.getError())
153*8bcb0991SDimitry Andric         return createFileError(FullPath, EC);
154*8bcb0991SDimitry Andric 
155*8bcb0991SDimitry Andric       // Keep the buffer alive.
156*8bcb0991SDimitry Andric       SeparateBuf = std::move(*BufferOrErr);
157*8bcb0991SDimitry Andric       Buf = SeparateBuf->getBuffer();
158*8bcb0991SDimitry Andric     }
159*8bcb0991SDimitry Andric   }
160*8bcb0991SDimitry Andric 
161*8bcb0991SDimitry Andric   std::unique_ptr<YAMLRemarkParser> Result =
162*8bcb0991SDimitry Andric       StrTab
163*8bcb0991SDimitry Andric           ? std::make_unique<YAMLStrTabRemarkParser>(Buf, std::move(*StrTab))
164*8bcb0991SDimitry Andric           : std::make_unique<YAMLRemarkParser>(Buf);
165*8bcb0991SDimitry Andric   if (SeparateBuf)
166*8bcb0991SDimitry Andric     Result->SeparateBuf = std::move(SeparateBuf);
167*8bcb0991SDimitry Andric   return std::move(Result);
168*8bcb0991SDimitry Andric }
169*8bcb0991SDimitry Andric 
170*8bcb0991SDimitry Andric YAMLRemarkParser::YAMLRemarkParser(StringRef Buf)
171*8bcb0991SDimitry Andric     : YAMLRemarkParser(Buf, None) {}
172*8bcb0991SDimitry Andric 
1730b57cec5SDimitry Andric YAMLRemarkParser::YAMLRemarkParser(StringRef Buf,
174*8bcb0991SDimitry Andric                                    Optional<ParsedStringTable> StrTab)
175*8bcb0991SDimitry Andric     : RemarkParser{Format::YAML}, StrTab(std::move(StrTab)), LastErrorMessage(),
1760b57cec5SDimitry Andric       SM(setupSM(LastErrorMessage)), Stream(Buf, SM), YAMLIt(Stream.begin()) {}
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric Error YAMLRemarkParser::error(StringRef Message, yaml::Node &Node) {
1790b57cec5SDimitry Andric   return make_error<YAMLParseError>(Message, SM, Stream, Node);
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric Error YAMLRemarkParser::error() {
1830b57cec5SDimitry Andric   if (LastErrorMessage.empty())
1840b57cec5SDimitry Andric     return Error::success();
1850b57cec5SDimitry Andric   Error E = make_error<YAMLParseError>(LastErrorMessage);
1860b57cec5SDimitry Andric   LastErrorMessage.clear();
1870b57cec5SDimitry Andric   return E;
1880b57cec5SDimitry Andric }
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric Expected<std::unique_ptr<Remark>>
1910b57cec5SDimitry Andric YAMLRemarkParser::parseRemark(yaml::Document &RemarkEntry) {
1920b57cec5SDimitry Andric   if (Error E = error())
1930b57cec5SDimitry Andric     return std::move(E);
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric   yaml::Node *YAMLRoot = RemarkEntry.getRoot();
1960b57cec5SDimitry Andric   if (!YAMLRoot) {
1970b57cec5SDimitry Andric     return createStringError(std::make_error_code(std::errc::invalid_argument),
1980b57cec5SDimitry Andric                              "not a valid YAML file.");
1990b57cec5SDimitry Andric   }
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   auto *Root = dyn_cast<yaml::MappingNode>(YAMLRoot);
2020b57cec5SDimitry Andric   if (!Root)
2030b57cec5SDimitry Andric     return error("document root is not of mapping type.", *YAMLRoot);
2040b57cec5SDimitry Andric 
205*8bcb0991SDimitry Andric   std::unique_ptr<Remark> Result = std::make_unique<Remark>();
2060b57cec5SDimitry Andric   Remark &TheRemark = *Result;
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric   // First, the type. It needs special handling since is not part of the
2090b57cec5SDimitry Andric   // key-value stream.
2100b57cec5SDimitry Andric   Expected<Type> T = parseType(*Root);
2110b57cec5SDimitry Andric   if (!T)
2120b57cec5SDimitry Andric     return T.takeError();
2130b57cec5SDimitry Andric   else
2140b57cec5SDimitry Andric     TheRemark.RemarkType = *T;
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric   // Then, parse the fields, one by one.
2170b57cec5SDimitry Andric   for (yaml::KeyValueNode &RemarkField : *Root) {
2180b57cec5SDimitry Andric     Expected<StringRef> MaybeKey = parseKey(RemarkField);
2190b57cec5SDimitry Andric     if (!MaybeKey)
2200b57cec5SDimitry Andric       return MaybeKey.takeError();
2210b57cec5SDimitry Andric     StringRef KeyName = *MaybeKey;
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric     if (KeyName == "Pass") {
2240b57cec5SDimitry Andric       if (Expected<StringRef> MaybeStr = parseStr(RemarkField))
2250b57cec5SDimitry Andric         TheRemark.PassName = *MaybeStr;
2260b57cec5SDimitry Andric       else
2270b57cec5SDimitry Andric         return MaybeStr.takeError();
2280b57cec5SDimitry Andric     } else if (KeyName == "Name") {
2290b57cec5SDimitry Andric       if (Expected<StringRef> MaybeStr = parseStr(RemarkField))
2300b57cec5SDimitry Andric         TheRemark.RemarkName = *MaybeStr;
2310b57cec5SDimitry Andric       else
2320b57cec5SDimitry Andric         return MaybeStr.takeError();
2330b57cec5SDimitry Andric     } else if (KeyName == "Function") {
2340b57cec5SDimitry Andric       if (Expected<StringRef> MaybeStr = parseStr(RemarkField))
2350b57cec5SDimitry Andric         TheRemark.FunctionName = *MaybeStr;
2360b57cec5SDimitry Andric       else
2370b57cec5SDimitry Andric         return MaybeStr.takeError();
2380b57cec5SDimitry Andric     } else if (KeyName == "Hotness") {
2390b57cec5SDimitry Andric       if (Expected<unsigned> MaybeU = parseUnsigned(RemarkField))
2400b57cec5SDimitry Andric         TheRemark.Hotness = *MaybeU;
2410b57cec5SDimitry Andric       else
2420b57cec5SDimitry Andric         return MaybeU.takeError();
2430b57cec5SDimitry Andric     } else if (KeyName == "DebugLoc") {
2440b57cec5SDimitry Andric       if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(RemarkField))
2450b57cec5SDimitry Andric         TheRemark.Loc = *MaybeLoc;
2460b57cec5SDimitry Andric       else
2470b57cec5SDimitry Andric         return MaybeLoc.takeError();
2480b57cec5SDimitry Andric     } else if (KeyName == "Args") {
2490b57cec5SDimitry Andric       auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue());
2500b57cec5SDimitry Andric       if (!Args)
2510b57cec5SDimitry Andric         return error("wrong value type for key.", RemarkField);
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric       for (yaml::Node &Arg : *Args) {
2540b57cec5SDimitry Andric         if (Expected<Argument> MaybeArg = parseArg(Arg))
2550b57cec5SDimitry Andric           TheRemark.Args.push_back(*MaybeArg);
2560b57cec5SDimitry Andric         else
2570b57cec5SDimitry Andric           return MaybeArg.takeError();
2580b57cec5SDimitry Andric       }
2590b57cec5SDimitry Andric     } else {
2600b57cec5SDimitry Andric       return error("unknown key.", RemarkField);
2610b57cec5SDimitry Andric     }
2620b57cec5SDimitry Andric   }
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric   // Check if any of the mandatory fields are missing.
2650b57cec5SDimitry Andric   if (TheRemark.RemarkType == Type::Unknown || TheRemark.PassName.empty() ||
2660b57cec5SDimitry Andric       TheRemark.RemarkName.empty() || TheRemark.FunctionName.empty())
2670b57cec5SDimitry Andric     return error("Type, Pass, Name or Function missing.",
2680b57cec5SDimitry Andric                  *RemarkEntry.getRoot());
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric   return std::move(Result);
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric Expected<Type> YAMLRemarkParser::parseType(yaml::MappingNode &Node) {
2740b57cec5SDimitry Andric   auto Type = StringSwitch<remarks::Type>(Node.getRawTag())
2750b57cec5SDimitry Andric                   .Case("!Passed", remarks::Type::Passed)
2760b57cec5SDimitry Andric                   .Case("!Missed", remarks::Type::Missed)
2770b57cec5SDimitry Andric                   .Case("!Analysis", remarks::Type::Analysis)
2780b57cec5SDimitry Andric                   .Case("!AnalysisFPCommute", remarks::Type::AnalysisFPCommute)
2790b57cec5SDimitry Andric                   .Case("!AnalysisAliasing", remarks::Type::AnalysisAliasing)
2800b57cec5SDimitry Andric                   .Case("!Failure", remarks::Type::Failure)
2810b57cec5SDimitry Andric                   .Default(remarks::Type::Unknown);
2820b57cec5SDimitry Andric   if (Type == remarks::Type::Unknown)
2830b57cec5SDimitry Andric     return error("expected a remark tag.", Node);
2840b57cec5SDimitry Andric   return Type;
2850b57cec5SDimitry Andric }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric Expected<StringRef> YAMLRemarkParser::parseKey(yaml::KeyValueNode &Node) {
2880b57cec5SDimitry Andric   if (auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey()))
2890b57cec5SDimitry Andric     return Key->getRawValue();
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric   return error("key is not a string.", Node);
2920b57cec5SDimitry Andric }
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric Expected<StringRef> YAMLRemarkParser::parseStr(yaml::KeyValueNode &Node) {
2950b57cec5SDimitry Andric   auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
2960b57cec5SDimitry Andric   if (!Value)
2970b57cec5SDimitry Andric     return error("expected a value of scalar type.", Node);
298*8bcb0991SDimitry Andric   StringRef Result = Value->getRawValue();
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric   if (Result.front() == '\'')
3010b57cec5SDimitry Andric     Result = Result.drop_front();
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric   if (Result.back() == '\'')
3040b57cec5SDimitry Andric     Result = Result.drop_back();
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric   return Result;
3070b57cec5SDimitry Andric }
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric Expected<unsigned> YAMLRemarkParser::parseUnsigned(yaml::KeyValueNode &Node) {
3100b57cec5SDimitry Andric   SmallVector<char, 4> Tmp;
3110b57cec5SDimitry Andric   auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
3120b57cec5SDimitry Andric   if (!Value)
3130b57cec5SDimitry Andric     return error("expected a value of scalar type.", Node);
3140b57cec5SDimitry Andric   unsigned UnsignedValue = 0;
3150b57cec5SDimitry Andric   if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue))
3160b57cec5SDimitry Andric     return error("expected a value of integer type.", *Value);
3170b57cec5SDimitry Andric   return UnsignedValue;
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric Expected<RemarkLocation>
3210b57cec5SDimitry Andric YAMLRemarkParser::parseDebugLoc(yaml::KeyValueNode &Node) {
3220b57cec5SDimitry Andric   auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue());
3230b57cec5SDimitry Andric   if (!DebugLoc)
3240b57cec5SDimitry Andric     return error("expected a value of mapping type.", Node);
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric   Optional<StringRef> File;
3270b57cec5SDimitry Andric   Optional<unsigned> Line;
3280b57cec5SDimitry Andric   Optional<unsigned> Column;
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   for (yaml::KeyValueNode &DLNode : *DebugLoc) {
3310b57cec5SDimitry Andric     Expected<StringRef> MaybeKey = parseKey(DLNode);
3320b57cec5SDimitry Andric     if (!MaybeKey)
3330b57cec5SDimitry Andric       return MaybeKey.takeError();
3340b57cec5SDimitry Andric     StringRef KeyName = *MaybeKey;
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric     if (KeyName == "File") {
3370b57cec5SDimitry Andric       if (Expected<StringRef> MaybeStr = parseStr(DLNode))
3380b57cec5SDimitry Andric         File = *MaybeStr;
3390b57cec5SDimitry Andric       else
3400b57cec5SDimitry Andric         return MaybeStr.takeError();
3410b57cec5SDimitry Andric     } else if (KeyName == "Column") {
3420b57cec5SDimitry Andric       if (Expected<unsigned> MaybeU = parseUnsigned(DLNode))
3430b57cec5SDimitry Andric         Column = *MaybeU;
3440b57cec5SDimitry Andric       else
3450b57cec5SDimitry Andric         return MaybeU.takeError();
3460b57cec5SDimitry Andric     } else if (KeyName == "Line") {
3470b57cec5SDimitry Andric       if (Expected<unsigned> MaybeU = parseUnsigned(DLNode))
3480b57cec5SDimitry Andric         Line = *MaybeU;
3490b57cec5SDimitry Andric       else
3500b57cec5SDimitry Andric         return MaybeU.takeError();
3510b57cec5SDimitry Andric     } else {
3520b57cec5SDimitry Andric       return error("unknown entry in DebugLoc map.", DLNode);
3530b57cec5SDimitry Andric     }
3540b57cec5SDimitry Andric   }
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric   // If any of the debug loc fields is missing, return an error.
3570b57cec5SDimitry Andric   if (!File || !Line || !Column)
3580b57cec5SDimitry Andric     return error("DebugLoc node incomplete.", Node);
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric   return RemarkLocation{*File, *Line, *Column};
3610b57cec5SDimitry Andric }
3620b57cec5SDimitry Andric 
3630b57cec5SDimitry Andric Expected<Argument> YAMLRemarkParser::parseArg(yaml::Node &Node) {
3640b57cec5SDimitry Andric   auto *ArgMap = dyn_cast<yaml::MappingNode>(&Node);
3650b57cec5SDimitry Andric   if (!ArgMap)
3660b57cec5SDimitry Andric     return error("expected a value of mapping type.", Node);
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   Optional<StringRef> KeyStr;
3690b57cec5SDimitry Andric   Optional<StringRef> ValueStr;
3700b57cec5SDimitry Andric   Optional<RemarkLocation> Loc;
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric   for (yaml::KeyValueNode &ArgEntry : *ArgMap) {
3730b57cec5SDimitry Andric     Expected<StringRef> MaybeKey = parseKey(ArgEntry);
3740b57cec5SDimitry Andric     if (!MaybeKey)
3750b57cec5SDimitry Andric       return MaybeKey.takeError();
3760b57cec5SDimitry Andric     StringRef KeyName = *MaybeKey;
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric     // Try to parse debug locs.
3790b57cec5SDimitry Andric     if (KeyName == "DebugLoc") {
3800b57cec5SDimitry Andric       // Can't have multiple DebugLoc entries per argument.
3810b57cec5SDimitry Andric       if (Loc)
3820b57cec5SDimitry Andric         return error("only one DebugLoc entry is allowed per argument.",
3830b57cec5SDimitry Andric                      ArgEntry);
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric       if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(ArgEntry)) {
3860b57cec5SDimitry Andric         Loc = *MaybeLoc;
3870b57cec5SDimitry Andric         continue;
3880b57cec5SDimitry Andric       } else
3890b57cec5SDimitry Andric         return MaybeLoc.takeError();
3900b57cec5SDimitry Andric     }
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric     // If we already have a string, error out.
3930b57cec5SDimitry Andric     if (ValueStr)
3940b57cec5SDimitry Andric       return error("only one string entry is allowed per argument.", ArgEntry);
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric     // Try to parse the value.
3970b57cec5SDimitry Andric     if (Expected<StringRef> MaybeStr = parseStr(ArgEntry))
3980b57cec5SDimitry Andric       ValueStr = *MaybeStr;
3990b57cec5SDimitry Andric     else
4000b57cec5SDimitry Andric       return MaybeStr.takeError();
4010b57cec5SDimitry Andric 
4020b57cec5SDimitry Andric     // Keep the key from the string.
4030b57cec5SDimitry Andric     KeyStr = KeyName;
4040b57cec5SDimitry Andric   }
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric   if (!KeyStr)
4070b57cec5SDimitry Andric     return error("argument key is missing.", *ArgMap);
4080b57cec5SDimitry Andric   if (!ValueStr)
4090b57cec5SDimitry Andric     return error("argument value is missing.", *ArgMap);
4100b57cec5SDimitry Andric 
4110b57cec5SDimitry Andric   return Argument{*KeyStr, *ValueStr, Loc};
4120b57cec5SDimitry Andric }
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric Expected<std::unique_ptr<Remark>> YAMLRemarkParser::next() {
4150b57cec5SDimitry Andric   if (YAMLIt == Stream.end())
4160b57cec5SDimitry Andric     return make_error<EndOfFileError>();
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric   Expected<std::unique_ptr<Remark>> MaybeResult = parseRemark(*YAMLIt);
4190b57cec5SDimitry Andric   if (!MaybeResult) {
4200b57cec5SDimitry Andric     // Avoid garbage input, set the iterator to the end.
4210b57cec5SDimitry Andric     YAMLIt = Stream.end();
4220b57cec5SDimitry Andric     return MaybeResult.takeError();
4230b57cec5SDimitry Andric   }
4240b57cec5SDimitry Andric 
4250b57cec5SDimitry Andric   ++YAMLIt;
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric   return std::move(*MaybeResult);
4280b57cec5SDimitry Andric }
429*8bcb0991SDimitry Andric 
430*8bcb0991SDimitry Andric Expected<StringRef> YAMLStrTabRemarkParser::parseStr(yaml::KeyValueNode &Node) {
431*8bcb0991SDimitry Andric   auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
432*8bcb0991SDimitry Andric   if (!Value)
433*8bcb0991SDimitry Andric     return error("expected a value of scalar type.", Node);
434*8bcb0991SDimitry Andric   StringRef Result;
435*8bcb0991SDimitry Andric   // If we have a string table, parse it as an unsigned.
436*8bcb0991SDimitry Andric   unsigned StrID = 0;
437*8bcb0991SDimitry Andric   if (Expected<unsigned> MaybeStrID = parseUnsigned(Node))
438*8bcb0991SDimitry Andric     StrID = *MaybeStrID;
439*8bcb0991SDimitry Andric   else
440*8bcb0991SDimitry Andric     return MaybeStrID.takeError();
441*8bcb0991SDimitry Andric 
442*8bcb0991SDimitry Andric   if (Expected<StringRef> Str = (*StrTab)[StrID])
443*8bcb0991SDimitry Andric     Result = *Str;
444*8bcb0991SDimitry Andric   else
445*8bcb0991SDimitry Andric     return Str.takeError();
446*8bcb0991SDimitry Andric 
447*8bcb0991SDimitry Andric   if (Result.front() == '\'')
448*8bcb0991SDimitry Andric     Result = Result.drop_front();
449*8bcb0991SDimitry Andric 
450*8bcb0991SDimitry Andric   if (Result.back() == '\'')
451*8bcb0991SDimitry Andric     Result = Result.drop_back();
452*8bcb0991SDimitry Andric 
453*8bcb0991SDimitry Andric   return Result;
454*8bcb0991SDimitry Andric }
455