xref: /llvm-project/llvm/lib/Remarks/YAMLRemarkParser.cpp (revision 4aea9f63a0a71ae20ad203e6e36c5894d95ae2a3)
15a05cc0eSFrancis Visoiu Mistrih //===- YAMLRemarkParser.cpp -----------------------------------------------===//
25a05cc0eSFrancis Visoiu Mistrih //
35a05cc0eSFrancis Visoiu Mistrih // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45a05cc0eSFrancis Visoiu Mistrih // See https://llvm.org/LICENSE.txt for license information.
55a05cc0eSFrancis Visoiu Mistrih // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65a05cc0eSFrancis Visoiu Mistrih //
75a05cc0eSFrancis Visoiu Mistrih //===----------------------------------------------------------------------===//
85a05cc0eSFrancis Visoiu Mistrih //
95a05cc0eSFrancis Visoiu Mistrih // This file provides utility methods used by clients that want to use the
105a05cc0eSFrancis Visoiu Mistrih // parser for remark diagnostics in LLVM.
115a05cc0eSFrancis Visoiu Mistrih //
125a05cc0eSFrancis Visoiu Mistrih //===----------------------------------------------------------------------===//
135a05cc0eSFrancis Visoiu Mistrih 
145a05cc0eSFrancis Visoiu Mistrih #include "YAMLRemarkParser.h"
15b0abd489SElliot Goodrich #include "llvm/ADT/SmallString.h"
165a05cc0eSFrancis Visoiu Mistrih #include "llvm/ADT/StringSwitch.h"
1764a5f9e1SFrancis Visoiu Mistrih #include "llvm/Support/Endian.h"
18684605ecSFrancis Visoiu Mistrih #include "llvm/Support/Path.h"
19f17dbb97SKazu Hirata #include <optional>
205a05cc0eSFrancis Visoiu Mistrih 
215a05cc0eSFrancis Visoiu Mistrih using namespace llvm;
225a05cc0eSFrancis Visoiu Mistrih using namespace llvm::remarks;
235a05cc0eSFrancis Visoiu Mistrih 
245a05cc0eSFrancis Visoiu Mistrih char YAMLParseError::ID = 0;
255a05cc0eSFrancis Visoiu Mistrih 
handleDiagnostic(const SMDiagnostic & Diag,void * Ctx)2694bad22cSFrancis Visoiu Mistrih static void handleDiagnostic(const SMDiagnostic &Diag, void *Ctx) {
2794bad22cSFrancis Visoiu Mistrih   assert(Ctx && "Expected non-null Ctx in diagnostic handler.");
2894bad22cSFrancis Visoiu Mistrih   std::string &Message = *static_cast<std::string *>(Ctx);
2994bad22cSFrancis Visoiu Mistrih   assert(Message.empty() && "Expected an empty string.");
3094bad22cSFrancis Visoiu Mistrih   raw_string_ostream OS(Message);
3194bad22cSFrancis Visoiu Mistrih   Diag.print(/*ProgName=*/nullptr, OS, /*ShowColors*/ false,
3294bad22cSFrancis Visoiu Mistrih              /*ShowKindLabels*/ true);
3394bad22cSFrancis Visoiu Mistrih   OS << '\n';
3494bad22cSFrancis Visoiu Mistrih   OS.flush();
3594bad22cSFrancis Visoiu Mistrih }
3694bad22cSFrancis Visoiu Mistrih 
YAMLParseError(StringRef Msg,SourceMgr & SM,yaml::Stream & Stream,yaml::Node & Node)3794bad22cSFrancis Visoiu Mistrih YAMLParseError::YAMLParseError(StringRef Msg, SourceMgr &SM,
3894bad22cSFrancis Visoiu Mistrih                                yaml::Stream &Stream, yaml::Node &Node) {
3994bad22cSFrancis Visoiu Mistrih   // 1) Set up a diagnostic handler to avoid errors being printed out to
4094bad22cSFrancis Visoiu Mistrih   // stderr.
4194bad22cSFrancis Visoiu Mistrih   // 2) Use the stream to print the error with the associated node.
4294bad22cSFrancis Visoiu Mistrih   // 3) The stream will use the source manager to print the error, which will
4394bad22cSFrancis Visoiu Mistrih   // call the diagnostic handler.
4494bad22cSFrancis Visoiu Mistrih   // 4) The diagnostic handler will stream the error directly into this object's
4594bad22cSFrancis Visoiu Mistrih   // Message member, which is used when logging is asked for.
4694bad22cSFrancis Visoiu Mistrih   auto OldDiagHandler = SM.getDiagHandler();
4794bad22cSFrancis Visoiu Mistrih   auto OldDiagCtx = SM.getDiagContext();
4894bad22cSFrancis Visoiu Mistrih   SM.setDiagHandler(handleDiagnostic, &Message);
4994bad22cSFrancis Visoiu Mistrih   Stream.printError(&Node, Twine(Msg) + Twine('\n'));
5094bad22cSFrancis Visoiu Mistrih   // Restore the old handlers.
5194bad22cSFrancis Visoiu Mistrih   SM.setDiagHandler(OldDiagHandler, OldDiagCtx);
5294bad22cSFrancis Visoiu Mistrih }
5394bad22cSFrancis Visoiu Mistrih 
setupSM(std::string & LastErrorMessage)5494bad22cSFrancis Visoiu Mistrih static SourceMgr setupSM(std::string &LastErrorMessage) {
5594bad22cSFrancis Visoiu Mistrih   SourceMgr SM;
5694bad22cSFrancis Visoiu Mistrih   SM.setDiagHandler(handleDiagnostic, &LastErrorMessage);
5794bad22cSFrancis Visoiu Mistrih   return SM;
5894bad22cSFrancis Visoiu Mistrih }
5994bad22cSFrancis Visoiu Mistrih 
6064a5f9e1SFrancis Visoiu Mistrih // Parse the magic number. This function returns true if this represents remark
6164a5f9e1SFrancis Visoiu Mistrih // metadata, false otherwise.
parseMagic(StringRef & Buf)6264a5f9e1SFrancis Visoiu Mistrih static Expected<bool> parseMagic(StringRef &Buf) {
6364a5f9e1SFrancis Visoiu Mistrih   if (!Buf.consume_front(remarks::Magic))
6464a5f9e1SFrancis Visoiu Mistrih     return false;
6564a5f9e1SFrancis Visoiu Mistrih 
6664a5f9e1SFrancis Visoiu Mistrih   if (Buf.size() < 1 || !Buf.consume_front(StringRef("\0", 1)))
6764a5f9e1SFrancis Visoiu Mistrih     return createStringError(std::errc::illegal_byte_sequence,
6864a5f9e1SFrancis Visoiu Mistrih                              "Expecting \\0 after magic number.");
6964a5f9e1SFrancis Visoiu Mistrih   return true;
7064a5f9e1SFrancis Visoiu Mistrih }
7164a5f9e1SFrancis Visoiu Mistrih 
parseVersion(StringRef & Buf)7264a5f9e1SFrancis Visoiu Mistrih static Expected<uint64_t> parseVersion(StringRef &Buf) {
7364a5f9e1SFrancis Visoiu Mistrih   if (Buf.size() < sizeof(uint64_t))
7464a5f9e1SFrancis Visoiu Mistrih     return createStringError(std::errc::illegal_byte_sequence,
7564a5f9e1SFrancis Visoiu Mistrih                              "Expecting version number.");
7664a5f9e1SFrancis Visoiu Mistrih 
7764a5f9e1SFrancis Visoiu Mistrih   uint64_t Version =
784a0ccfa8SKazu Hirata       support::endian::read<uint64_t, llvm::endianness::little>(Buf.data());
7984e80979SFrancis Visoiu Mistrih   if (Version != remarks::CurrentRemarkVersion)
8072d00802SFrancis Visoiu Mistrih     return createStringError(std::errc::illegal_byte_sequence,
8172d00802SFrancis Visoiu Mistrih                              "Mismatching remark version. Got %" PRId64
8272d00802SFrancis Visoiu Mistrih                              ", expected %" PRId64 ".",
8384e80979SFrancis Visoiu Mistrih                              Version, remarks::CurrentRemarkVersion);
8464a5f9e1SFrancis Visoiu Mistrih   Buf = Buf.drop_front(sizeof(uint64_t));
8564a5f9e1SFrancis Visoiu Mistrih   return Version;
8664a5f9e1SFrancis Visoiu Mistrih }
8764a5f9e1SFrancis Visoiu Mistrih 
parseStrTabSize(StringRef & Buf)8864a5f9e1SFrancis Visoiu Mistrih static Expected<uint64_t> parseStrTabSize(StringRef &Buf) {
8964a5f9e1SFrancis Visoiu Mistrih   if (Buf.size() < sizeof(uint64_t))
9064a5f9e1SFrancis Visoiu Mistrih     return createStringError(std::errc::illegal_byte_sequence,
9164a5f9e1SFrancis Visoiu Mistrih                              "Expecting string table size.");
9264a5f9e1SFrancis Visoiu Mistrih   uint64_t StrTabSize =
934a0ccfa8SKazu Hirata       support::endian::read<uint64_t, llvm::endianness::little>(Buf.data());
9464a5f9e1SFrancis Visoiu Mistrih   Buf = Buf.drop_front(sizeof(uint64_t));
9564a5f9e1SFrancis Visoiu Mistrih   return StrTabSize;
9664a5f9e1SFrancis Visoiu Mistrih }
9764a5f9e1SFrancis Visoiu Mistrih 
parseStrTab(StringRef & Buf,uint64_t StrTabSize)9864a5f9e1SFrancis Visoiu Mistrih static Expected<ParsedStringTable> parseStrTab(StringRef &Buf,
9964a5f9e1SFrancis Visoiu Mistrih                                                uint64_t StrTabSize) {
10064a5f9e1SFrancis Visoiu Mistrih   if (Buf.size() < StrTabSize)
10164a5f9e1SFrancis Visoiu Mistrih     return createStringError(std::errc::illegal_byte_sequence,
10264a5f9e1SFrancis Visoiu Mistrih                              "Expecting string table.");
10364a5f9e1SFrancis Visoiu Mistrih 
10464a5f9e1SFrancis Visoiu Mistrih   // Attach the string table to the parser.
10564a5f9e1SFrancis Visoiu Mistrih   ParsedStringTable Result(StringRef(Buf.data(), StrTabSize));
10664a5f9e1SFrancis Visoiu Mistrih   Buf = Buf.drop_front(StrTabSize);
10764a5f9e1SFrancis Visoiu Mistrih   return Expected<ParsedStringTable>(std::move(Result));
10864a5f9e1SFrancis Visoiu Mistrih }
10964a5f9e1SFrancis Visoiu Mistrih 
createYAMLParserFromMeta(StringRef Buf,std::optional<ParsedStringTable> StrTab,std::optional<StringRef> ExternalFilePrependPath)110a81a0c97SKrzysztof Parzyszek Expected<std::unique_ptr<YAMLRemarkParser>> remarks::createYAMLParserFromMeta(
111a81a0c97SKrzysztof Parzyszek     StringRef Buf, std::optional<ParsedStringTable> StrTab,
112a81a0c97SKrzysztof Parzyszek     std::optional<StringRef> ExternalFilePrependPath) {
11364a5f9e1SFrancis Visoiu Mistrih   // We now have a magic number. The metadata has to be correct.
11464a5f9e1SFrancis Visoiu Mistrih   Expected<bool> isMeta = parseMagic(Buf);
11564a5f9e1SFrancis Visoiu Mistrih   if (!isMeta)
11664a5f9e1SFrancis Visoiu Mistrih     return isMeta.takeError();
11764a5f9e1SFrancis Visoiu Mistrih   // If it's not recognized as metadata, roll back.
11864a5f9e1SFrancis Visoiu Mistrih   std::unique_ptr<MemoryBuffer> SeparateBuf;
11964a5f9e1SFrancis Visoiu Mistrih   if (*isMeta) {
12064a5f9e1SFrancis Visoiu Mistrih     Expected<uint64_t> Version = parseVersion(Buf);
12164a5f9e1SFrancis Visoiu Mistrih     if (!Version)
12264a5f9e1SFrancis Visoiu Mistrih       return Version.takeError();
12364a5f9e1SFrancis Visoiu Mistrih 
12464a5f9e1SFrancis Visoiu Mistrih     Expected<uint64_t> StrTabSize = parseStrTabSize(Buf);
12564a5f9e1SFrancis Visoiu Mistrih     if (!StrTabSize)
12664a5f9e1SFrancis Visoiu Mistrih       return StrTabSize.takeError();
12764a5f9e1SFrancis Visoiu Mistrih 
12864a5f9e1SFrancis Visoiu Mistrih     // If the size of string table is not 0, try to build one.
12964a5f9e1SFrancis Visoiu Mistrih     if (*StrTabSize != 0) {
13064a5f9e1SFrancis Visoiu Mistrih       if (StrTab)
13164a5f9e1SFrancis Visoiu Mistrih         return createStringError(std::errc::illegal_byte_sequence,
13264a5f9e1SFrancis Visoiu Mistrih                                  "String table already provided.");
13364a5f9e1SFrancis Visoiu Mistrih       Expected<ParsedStringTable> MaybeStrTab = parseStrTab(Buf, *StrTabSize);
13464a5f9e1SFrancis Visoiu Mistrih       if (!MaybeStrTab)
13564a5f9e1SFrancis Visoiu Mistrih         return MaybeStrTab.takeError();
13664a5f9e1SFrancis Visoiu Mistrih       StrTab = std::move(*MaybeStrTab);
13764a5f9e1SFrancis Visoiu Mistrih     }
13864a5f9e1SFrancis Visoiu Mistrih     // If it starts with "---", there is no external file.
139586ecdf2SKazu Hirata     if (!Buf.starts_with("---")) {
14064a5f9e1SFrancis Visoiu Mistrih       // At this point, we expect Buf to contain the external file path.
141684605ecSFrancis Visoiu Mistrih       StringRef ExternalFilePath = Buf;
142684605ecSFrancis Visoiu Mistrih       SmallString<80> FullPath;
143684605ecSFrancis Visoiu Mistrih       if (ExternalFilePrependPath)
144684605ecSFrancis Visoiu Mistrih         FullPath = *ExternalFilePrependPath;
145684605ecSFrancis Visoiu Mistrih       sys::path::append(FullPath, ExternalFilePath);
146684605ecSFrancis Visoiu Mistrih 
14764a5f9e1SFrancis Visoiu Mistrih       // Try to open the file and start parsing from there.
14864a5f9e1SFrancis Visoiu Mistrih       ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
149684605ecSFrancis Visoiu Mistrih           MemoryBuffer::getFile(FullPath);
15064a5f9e1SFrancis Visoiu Mistrih       if (std::error_code EC = BufferOrErr.getError())
151684605ecSFrancis Visoiu Mistrih         return createFileError(FullPath, EC);
15264a5f9e1SFrancis Visoiu Mistrih 
15364a5f9e1SFrancis Visoiu Mistrih       // Keep the buffer alive.
15464a5f9e1SFrancis Visoiu Mistrih       SeparateBuf = std::move(*BufferOrErr);
15564a5f9e1SFrancis Visoiu Mistrih       Buf = SeparateBuf->getBuffer();
15664a5f9e1SFrancis Visoiu Mistrih     }
15764a5f9e1SFrancis Visoiu Mistrih   }
15864a5f9e1SFrancis Visoiu Mistrih 
15964a5f9e1SFrancis Visoiu Mistrih   std::unique_ptr<YAMLRemarkParser> Result =
16064a5f9e1SFrancis Visoiu Mistrih       StrTab
1610eaee545SJonas Devlieghere           ? std::make_unique<YAMLStrTabRemarkParser>(Buf, std::move(*StrTab))
1620eaee545SJonas Devlieghere           : std::make_unique<YAMLRemarkParser>(Buf);
16364a5f9e1SFrancis Visoiu Mistrih   if (SeparateBuf)
16464a5f9e1SFrancis Visoiu Mistrih     Result->SeparateBuf = std::move(SeparateBuf);
165c55cf4afSBill Wendling   return std::move(Result);
16664a5f9e1SFrancis Visoiu Mistrih }
16764a5f9e1SFrancis Visoiu Mistrih 
YAMLRemarkParser(StringRef Buf)168c5b5cc45SFrancis Visoiu Mistrih YAMLRemarkParser::YAMLRemarkParser(StringRef Buf)
169aadaafacSKazu Hirata     : YAMLRemarkParser(Buf, std::nullopt) {}
170c5b5cc45SFrancis Visoiu Mistrih 
YAMLRemarkParser(StringRef Buf,std::optional<ParsedStringTable> StrTab)17194bad22cSFrancis Visoiu Mistrih YAMLRemarkParser::YAMLRemarkParser(StringRef Buf,
172a81a0c97SKrzysztof Parzyszek                                    std::optional<ParsedStringTable> StrTab)
173b932bdf5SKazu Hirata     : RemarkParser{Format::YAML}, StrTab(std::move(StrTab)),
17494bad22cSFrancis Visoiu Mistrih       SM(setupSM(LastErrorMessage)), Stream(Buf, SM), YAMLIt(Stream.begin()) {}
17594bad22cSFrancis Visoiu Mistrih 
error(StringRef Message,yaml::Node & Node)17694bad22cSFrancis Visoiu Mistrih Error YAMLRemarkParser::error(StringRef Message, yaml::Node &Node) {
17794bad22cSFrancis Visoiu Mistrih   return make_error<YAMLParseError>(Message, SM, Stream, Node);
17894bad22cSFrancis Visoiu Mistrih }
17994bad22cSFrancis Visoiu Mistrih 
error()18094bad22cSFrancis Visoiu Mistrih Error YAMLRemarkParser::error() {
18194bad22cSFrancis Visoiu Mistrih   if (LastErrorMessage.empty())
1825a05cc0eSFrancis Visoiu Mistrih     return Error::success();
18394bad22cSFrancis Visoiu Mistrih   Error E = make_error<YAMLParseError>(LastErrorMessage);
18494bad22cSFrancis Visoiu Mistrih   LastErrorMessage.clear();
1857fee2b89SFrancis Visoiu Mistrih   return E;
18694bad22cSFrancis Visoiu Mistrih }
18794bad22cSFrancis Visoiu Mistrih 
18894bad22cSFrancis Visoiu Mistrih Expected<std::unique_ptr<Remark>>
parseRemark(yaml::Document & RemarkEntry)18994bad22cSFrancis Visoiu Mistrih YAMLRemarkParser::parseRemark(yaml::Document &RemarkEntry) {
19094bad22cSFrancis Visoiu Mistrih   if (Error E = error())
191c55cf4afSBill Wendling     return std::move(E);
19294bad22cSFrancis Visoiu Mistrih 
19394bad22cSFrancis Visoiu Mistrih   yaml::Node *YAMLRoot = RemarkEntry.getRoot();
19494bad22cSFrancis Visoiu Mistrih   if (!YAMLRoot) {
19594bad22cSFrancis Visoiu Mistrih     return createStringError(std::make_error_code(std::errc::invalid_argument),
19694bad22cSFrancis Visoiu Mistrih                              "not a valid YAML file.");
19794bad22cSFrancis Visoiu Mistrih   }
19894bad22cSFrancis Visoiu Mistrih 
19994bad22cSFrancis Visoiu Mistrih   auto *Root = dyn_cast<yaml::MappingNode>(YAMLRoot);
20094bad22cSFrancis Visoiu Mistrih   if (!Root)
20194bad22cSFrancis Visoiu Mistrih     return error("document root is not of mapping type.", *YAMLRoot);
20294bad22cSFrancis Visoiu Mistrih 
2030eaee545SJonas Devlieghere   std::unique_ptr<Remark> Result = std::make_unique<Remark>();
20494bad22cSFrancis Visoiu Mistrih   Remark &TheRemark = *Result;
20594bad22cSFrancis Visoiu Mistrih 
20694bad22cSFrancis Visoiu Mistrih   // First, the type. It needs special handling since is not part of the
20794bad22cSFrancis Visoiu Mistrih   // key-value stream.
20894bad22cSFrancis Visoiu Mistrih   Expected<Type> T = parseType(*Root);
20994bad22cSFrancis Visoiu Mistrih   if (!T)
21094bad22cSFrancis Visoiu Mistrih     return T.takeError();
2117fee2b89SFrancis Visoiu Mistrih   else
21294bad22cSFrancis Visoiu Mistrih     TheRemark.RemarkType = *T;
21394bad22cSFrancis Visoiu Mistrih 
21494bad22cSFrancis Visoiu Mistrih   // Then, parse the fields, one by one.
21594bad22cSFrancis Visoiu Mistrih   for (yaml::KeyValueNode &RemarkField : *Root) {
21694bad22cSFrancis Visoiu Mistrih     Expected<StringRef> MaybeKey = parseKey(RemarkField);
21794bad22cSFrancis Visoiu Mistrih     if (!MaybeKey)
21894bad22cSFrancis Visoiu Mistrih       return MaybeKey.takeError();
21994bad22cSFrancis Visoiu Mistrih     StringRef KeyName = *MaybeKey;
22094bad22cSFrancis Visoiu Mistrih 
22194bad22cSFrancis Visoiu Mistrih     if (KeyName == "Pass") {
22294bad22cSFrancis Visoiu Mistrih       if (Expected<StringRef> MaybeStr = parseStr(RemarkField))
22394bad22cSFrancis Visoiu Mistrih         TheRemark.PassName = *MaybeStr;
22494bad22cSFrancis Visoiu Mistrih       else
22594bad22cSFrancis Visoiu Mistrih         return MaybeStr.takeError();
22694bad22cSFrancis Visoiu Mistrih     } else if (KeyName == "Name") {
22794bad22cSFrancis Visoiu Mistrih       if (Expected<StringRef> MaybeStr = parseStr(RemarkField))
22894bad22cSFrancis Visoiu Mistrih         TheRemark.RemarkName = *MaybeStr;
22994bad22cSFrancis Visoiu Mistrih       else
23094bad22cSFrancis Visoiu Mistrih         return MaybeStr.takeError();
23194bad22cSFrancis Visoiu Mistrih     } else if (KeyName == "Function") {
23294bad22cSFrancis Visoiu Mistrih       if (Expected<StringRef> MaybeStr = parseStr(RemarkField))
23394bad22cSFrancis Visoiu Mistrih         TheRemark.FunctionName = *MaybeStr;
23494bad22cSFrancis Visoiu Mistrih       else
23594bad22cSFrancis Visoiu Mistrih         return MaybeStr.takeError();
23694bad22cSFrancis Visoiu Mistrih     } else if (KeyName == "Hotness") {
23794bad22cSFrancis Visoiu Mistrih       if (Expected<unsigned> MaybeU = parseUnsigned(RemarkField))
23894bad22cSFrancis Visoiu Mistrih         TheRemark.Hotness = *MaybeU;
23994bad22cSFrancis Visoiu Mistrih       else
24094bad22cSFrancis Visoiu Mistrih         return MaybeU.takeError();
24194bad22cSFrancis Visoiu Mistrih     } else if (KeyName == "DebugLoc") {
24294bad22cSFrancis Visoiu Mistrih       if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(RemarkField))
24394bad22cSFrancis Visoiu Mistrih         TheRemark.Loc = *MaybeLoc;
24494bad22cSFrancis Visoiu Mistrih       else
24594bad22cSFrancis Visoiu Mistrih         return MaybeLoc.takeError();
24694bad22cSFrancis Visoiu Mistrih     } else if (KeyName == "Args") {
24794bad22cSFrancis Visoiu Mistrih       auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue());
24894bad22cSFrancis Visoiu Mistrih       if (!Args)
24994bad22cSFrancis Visoiu Mistrih         return error("wrong value type for key.", RemarkField);
25094bad22cSFrancis Visoiu Mistrih 
25194bad22cSFrancis Visoiu Mistrih       for (yaml::Node &Arg : *Args) {
25294bad22cSFrancis Visoiu Mistrih         if (Expected<Argument> MaybeArg = parseArg(Arg))
25394bad22cSFrancis Visoiu Mistrih           TheRemark.Args.push_back(*MaybeArg);
25494bad22cSFrancis Visoiu Mistrih         else
25594bad22cSFrancis Visoiu Mistrih           return MaybeArg.takeError();
25694bad22cSFrancis Visoiu Mistrih       }
25794bad22cSFrancis Visoiu Mistrih     } else {
25894bad22cSFrancis Visoiu Mistrih       return error("unknown key.", RemarkField);
25994bad22cSFrancis Visoiu Mistrih     }
2607fee2b89SFrancis Visoiu Mistrih   }
2615a05cc0eSFrancis Visoiu Mistrih 
26294bad22cSFrancis Visoiu Mistrih   // Check if any of the mandatory fields are missing.
26394bad22cSFrancis Visoiu Mistrih   if (TheRemark.RemarkType == Type::Unknown || TheRemark.PassName.empty() ||
26494bad22cSFrancis Visoiu Mistrih       TheRemark.RemarkName.empty() || TheRemark.FunctionName.empty())
26594bad22cSFrancis Visoiu Mistrih     return error("Type, Pass, Name or Function missing.",
26694bad22cSFrancis Visoiu Mistrih                  *RemarkEntry.getRoot());
2675a05cc0eSFrancis Visoiu Mistrih 
268c55cf4afSBill Wendling   return std::move(Result);
2695a05cc0eSFrancis Visoiu Mistrih }
2705a05cc0eSFrancis Visoiu Mistrih 
parseType(yaml::MappingNode & Node)27194bad22cSFrancis Visoiu Mistrih Expected<Type> YAMLRemarkParser::parseType(yaml::MappingNode &Node) {
2725a05cc0eSFrancis Visoiu Mistrih   auto Type = StringSwitch<remarks::Type>(Node.getRawTag())
2735616718cSFrancis Visoiu Mistrih                   .Case("!Passed", remarks::Type::Passed)
2745616718cSFrancis Visoiu Mistrih                   .Case("!Missed", remarks::Type::Missed)
2755616718cSFrancis Visoiu Mistrih                   .Case("!Analysis", remarks::Type::Analysis)
2765616718cSFrancis Visoiu Mistrih                   .Case("!AnalysisFPCommute", remarks::Type::AnalysisFPCommute)
2775616718cSFrancis Visoiu Mistrih                   .Case("!AnalysisAliasing", remarks::Type::AnalysisAliasing)
2785616718cSFrancis Visoiu Mistrih                   .Case("!Failure", remarks::Type::Failure)
2795616718cSFrancis Visoiu Mistrih                   .Default(remarks::Type::Unknown);
2805616718cSFrancis Visoiu Mistrih   if (Type == remarks::Type::Unknown)
28194bad22cSFrancis Visoiu Mistrih     return error("expected a remark tag.", Node);
28294bad22cSFrancis Visoiu Mistrih   return Type;
2835a05cc0eSFrancis Visoiu Mistrih }
2845a05cc0eSFrancis Visoiu Mistrih 
parseKey(yaml::KeyValueNode & Node)28594bad22cSFrancis Visoiu Mistrih Expected<StringRef> YAMLRemarkParser::parseKey(yaml::KeyValueNode &Node) {
28694bad22cSFrancis Visoiu Mistrih   if (auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey()))
28794bad22cSFrancis Visoiu Mistrih     return Key->getRawValue();
28894bad22cSFrancis Visoiu Mistrih 
28994bad22cSFrancis Visoiu Mistrih   return error("key is not a string.", Node);
29094bad22cSFrancis Visoiu Mistrih }
29194bad22cSFrancis Visoiu Mistrih 
parseStr(yaml::KeyValueNode & Node)29294bad22cSFrancis Visoiu Mistrih Expected<StringRef> YAMLRemarkParser::parseStr(yaml::KeyValueNode &Node) {
29394bad22cSFrancis Visoiu Mistrih   auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
294e800967eSZain Jaffal   yaml::BlockScalarNode *ValueBlock;
295e800967eSZain Jaffal   StringRef Result;
296e800967eSZain Jaffal   if (!Value) {
297e800967eSZain Jaffal     // Try to parse the value as a block node.
298e800967eSZain Jaffal     ValueBlock = dyn_cast<yaml::BlockScalarNode>(Node.getValue());
299e800967eSZain Jaffal     if (!ValueBlock)
30094bad22cSFrancis Visoiu Mistrih       return error("expected a value of scalar type.", Node);
301e800967eSZain Jaffal     Result = ValueBlock->getValue();
302e800967eSZain Jaffal   } else
303e800967eSZain Jaffal     Result = Value->getRawValue();
30494bad22cSFrancis Visoiu Mistrih 
305*4aea9f63SKazu Hirata   Result.consume_front("\'");
306*4aea9f63SKazu Hirata   Result.consume_back("\'");
30794bad22cSFrancis Visoiu Mistrih 
30894bad22cSFrancis Visoiu Mistrih   return Result;
30994bad22cSFrancis Visoiu Mistrih }
31094bad22cSFrancis Visoiu Mistrih 
parseUnsigned(yaml::KeyValueNode & Node)31194bad22cSFrancis Visoiu Mistrih Expected<unsigned> YAMLRemarkParser::parseUnsigned(yaml::KeyValueNode &Node) {
31294bad22cSFrancis Visoiu Mistrih   SmallVector<char, 4> Tmp;
31394bad22cSFrancis Visoiu Mistrih   auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
31494bad22cSFrancis Visoiu Mistrih   if (!Value)
31594bad22cSFrancis Visoiu Mistrih     return error("expected a value of scalar type.", Node);
31694bad22cSFrancis Visoiu Mistrih   unsigned UnsignedValue = 0;
31794bad22cSFrancis Visoiu Mistrih   if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue))
31894bad22cSFrancis Visoiu Mistrih     return error("expected a value of integer type.", *Value);
31994bad22cSFrancis Visoiu Mistrih   return UnsignedValue;
32094bad22cSFrancis Visoiu Mistrih }
32194bad22cSFrancis Visoiu Mistrih 
32294bad22cSFrancis Visoiu Mistrih Expected<RemarkLocation>
parseDebugLoc(yaml::KeyValueNode & Node)32394bad22cSFrancis Visoiu Mistrih YAMLRemarkParser::parseDebugLoc(yaml::KeyValueNode &Node) {
3245a05cc0eSFrancis Visoiu Mistrih   auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue());
3255a05cc0eSFrancis Visoiu Mistrih   if (!DebugLoc)
32694bad22cSFrancis Visoiu Mistrih     return error("expected a value of mapping type.", Node);
3275a05cc0eSFrancis Visoiu Mistrih 
328f17dbb97SKazu Hirata   std::optional<StringRef> File;
329f17dbb97SKazu Hirata   std::optional<unsigned> Line;
330f17dbb97SKazu Hirata   std::optional<unsigned> Column;
3315a05cc0eSFrancis Visoiu Mistrih 
3325a05cc0eSFrancis Visoiu Mistrih   for (yaml::KeyValueNode &DLNode : *DebugLoc) {
33394bad22cSFrancis Visoiu Mistrih     Expected<StringRef> MaybeKey = parseKey(DLNode);
33494bad22cSFrancis Visoiu Mistrih     if (!MaybeKey)
33594bad22cSFrancis Visoiu Mistrih       return MaybeKey.takeError();
33694bad22cSFrancis Visoiu Mistrih     StringRef KeyName = *MaybeKey;
33794bad22cSFrancis Visoiu Mistrih 
3385a05cc0eSFrancis Visoiu Mistrih     if (KeyName == "File") {
33994bad22cSFrancis Visoiu Mistrih       if (Expected<StringRef> MaybeStr = parseStr(DLNode))
34094bad22cSFrancis Visoiu Mistrih         File = *MaybeStr;
34194bad22cSFrancis Visoiu Mistrih       else
34294bad22cSFrancis Visoiu Mistrih         return MaybeStr.takeError();
3435a05cc0eSFrancis Visoiu Mistrih     } else if (KeyName == "Column") {
34494bad22cSFrancis Visoiu Mistrih       if (Expected<unsigned> MaybeU = parseUnsigned(DLNode))
34594bad22cSFrancis Visoiu Mistrih         Column = *MaybeU;
34694bad22cSFrancis Visoiu Mistrih       else
34794bad22cSFrancis Visoiu Mistrih         return MaybeU.takeError();
3485a05cc0eSFrancis Visoiu Mistrih     } else if (KeyName == "Line") {
34994bad22cSFrancis Visoiu Mistrih       if (Expected<unsigned> MaybeU = parseUnsigned(DLNode))
35094bad22cSFrancis Visoiu Mistrih         Line = *MaybeU;
35194bad22cSFrancis Visoiu Mistrih       else
35294bad22cSFrancis Visoiu Mistrih         return MaybeU.takeError();
3535a05cc0eSFrancis Visoiu Mistrih     } else {
35494bad22cSFrancis Visoiu Mistrih       return error("unknown entry in DebugLoc map.", DLNode);
3555a05cc0eSFrancis Visoiu Mistrih     }
3565a05cc0eSFrancis Visoiu Mistrih   }
3575a05cc0eSFrancis Visoiu Mistrih 
3585a05cc0eSFrancis Visoiu Mistrih   // If any of the debug loc fields is missing, return an error.
3595a05cc0eSFrancis Visoiu Mistrih   if (!File || !Line || !Column)
36094bad22cSFrancis Visoiu Mistrih     return error("DebugLoc node incomplete.", Node);
3615a05cc0eSFrancis Visoiu Mistrih 
36294bad22cSFrancis Visoiu Mistrih   return RemarkLocation{*File, *Line, *Column};
3635a05cc0eSFrancis Visoiu Mistrih }
3645a05cc0eSFrancis Visoiu Mistrih 
parseArg(yaml::Node & Node)36594bad22cSFrancis Visoiu Mistrih Expected<Argument> YAMLRemarkParser::parseArg(yaml::Node &Node) {
3665a05cc0eSFrancis Visoiu Mistrih   auto *ArgMap = dyn_cast<yaml::MappingNode>(&Node);
3675a05cc0eSFrancis Visoiu Mistrih   if (!ArgMap)
36894bad22cSFrancis Visoiu Mistrih     return error("expected a value of mapping type.", Node);
3695a05cc0eSFrancis Visoiu Mistrih 
370f17dbb97SKazu Hirata   std::optional<StringRef> KeyStr;
371f17dbb97SKazu Hirata   std::optional<StringRef> ValueStr;
372c589730aSKrzysztof Parzyszek   std::optional<RemarkLocation> Loc;
3735a05cc0eSFrancis Visoiu Mistrih 
37494bad22cSFrancis Visoiu Mistrih   for (yaml::KeyValueNode &ArgEntry : *ArgMap) {
37594bad22cSFrancis Visoiu Mistrih     Expected<StringRef> MaybeKey = parseKey(ArgEntry);
37694bad22cSFrancis Visoiu Mistrih     if (!MaybeKey)
37794bad22cSFrancis Visoiu Mistrih       return MaybeKey.takeError();
37894bad22cSFrancis Visoiu Mistrih     StringRef KeyName = *MaybeKey;
3795a05cc0eSFrancis Visoiu Mistrih 
3805a05cc0eSFrancis Visoiu Mistrih     // Try to parse debug locs.
3815a05cc0eSFrancis Visoiu Mistrih     if (KeyName == "DebugLoc") {
3825a05cc0eSFrancis Visoiu Mistrih       // Can't have multiple DebugLoc entries per argument.
3835a05cc0eSFrancis Visoiu Mistrih       if (Loc)
38494bad22cSFrancis Visoiu Mistrih         return error("only one DebugLoc entry is allowed per argument.",
38594bad22cSFrancis Visoiu Mistrih                      ArgEntry);
3865a05cc0eSFrancis Visoiu Mistrih 
38794bad22cSFrancis Visoiu Mistrih       if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(ArgEntry)) {
38894bad22cSFrancis Visoiu Mistrih         Loc = *MaybeLoc;
38994bad22cSFrancis Visoiu Mistrih         continue;
39094bad22cSFrancis Visoiu Mistrih       } else
39194bad22cSFrancis Visoiu Mistrih         return MaybeLoc.takeError();
3925a05cc0eSFrancis Visoiu Mistrih     }
3935a05cc0eSFrancis Visoiu Mistrih 
3945a05cc0eSFrancis Visoiu Mistrih     // If we already have a string, error out.
39594bad22cSFrancis Visoiu Mistrih     if (ValueStr)
39694bad22cSFrancis Visoiu Mistrih       return error("only one string entry is allowed per argument.", ArgEntry);
3975a05cc0eSFrancis Visoiu Mistrih 
39894bad22cSFrancis Visoiu Mistrih     // Try to parse the value.
39994bad22cSFrancis Visoiu Mistrih     if (Expected<StringRef> MaybeStr = parseStr(ArgEntry))
40094bad22cSFrancis Visoiu Mistrih       ValueStr = *MaybeStr;
40194bad22cSFrancis Visoiu Mistrih     else
40294bad22cSFrancis Visoiu Mistrih       return MaybeStr.takeError();
4035a05cc0eSFrancis Visoiu Mistrih 
4045a05cc0eSFrancis Visoiu Mistrih     // Keep the key from the string.
4055a05cc0eSFrancis Visoiu Mistrih     KeyStr = KeyName;
4065a05cc0eSFrancis Visoiu Mistrih   }
4075a05cc0eSFrancis Visoiu Mistrih 
40894bad22cSFrancis Visoiu Mistrih   if (!KeyStr)
40994bad22cSFrancis Visoiu Mistrih     return error("argument key is missing.", *ArgMap);
41094bad22cSFrancis Visoiu Mistrih   if (!ValueStr)
41194bad22cSFrancis Visoiu Mistrih     return error("argument value is missing.", *ArgMap);
4125a05cc0eSFrancis Visoiu Mistrih 
41394bad22cSFrancis Visoiu Mistrih   return Argument{*KeyStr, *ValueStr, Loc};
4145a05cc0eSFrancis Visoiu Mistrih }
4155a05cc0eSFrancis Visoiu Mistrih 
next()41694bad22cSFrancis Visoiu Mistrih Expected<std::unique_ptr<Remark>> YAMLRemarkParser::next() {
41794bad22cSFrancis Visoiu Mistrih   if (YAMLIt == Stream.end())
41894bad22cSFrancis Visoiu Mistrih     return make_error<EndOfFileError>();
41994bad22cSFrancis Visoiu Mistrih 
42094bad22cSFrancis Visoiu Mistrih   Expected<std::unique_ptr<Remark>> MaybeResult = parseRemark(*YAMLIt);
42194bad22cSFrancis Visoiu Mistrih   if (!MaybeResult) {
42294bad22cSFrancis Visoiu Mistrih     // Avoid garbage input, set the iterator to the end.
42394bad22cSFrancis Visoiu Mistrih     YAMLIt = Stream.end();
42494bad22cSFrancis Visoiu Mistrih     return MaybeResult.takeError();
42594bad22cSFrancis Visoiu Mistrih   }
42694bad22cSFrancis Visoiu Mistrih 
42794bad22cSFrancis Visoiu Mistrih   ++YAMLIt;
42894bad22cSFrancis Visoiu Mistrih 
42994bad22cSFrancis Visoiu Mistrih   return std::move(*MaybeResult);
4305a05cc0eSFrancis Visoiu Mistrih }
431c5b5cc45SFrancis Visoiu Mistrih 
parseStr(yaml::KeyValueNode & Node)432c5b5cc45SFrancis Visoiu Mistrih Expected<StringRef> YAMLStrTabRemarkParser::parseStr(yaml::KeyValueNode &Node) {
433c5b5cc45SFrancis Visoiu Mistrih   auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
434e800967eSZain Jaffal   yaml::BlockScalarNode *ValueBlock;
435c5b5cc45SFrancis Visoiu Mistrih   StringRef Result;
436e800967eSZain Jaffal   if (!Value) {
437e800967eSZain Jaffal     // Try to parse the value as a block node.
438e800967eSZain Jaffal     ValueBlock = dyn_cast<yaml::BlockScalarNode>(Node.getValue());
439e800967eSZain Jaffal     if (!ValueBlock)
440e800967eSZain Jaffal       return error("expected a value of scalar type.", Node);
441e800967eSZain Jaffal     Result = ValueBlock->getValue();
442e800967eSZain Jaffal   } else
443e800967eSZain Jaffal     Result = Value->getRawValue();
444c5b5cc45SFrancis Visoiu Mistrih   // If we have a string table, parse it as an unsigned.
445c5b5cc45SFrancis Visoiu Mistrih   unsigned StrID = 0;
446c5b5cc45SFrancis Visoiu Mistrih   if (Expected<unsigned> MaybeStrID = parseUnsigned(Node))
447c5b5cc45SFrancis Visoiu Mistrih     StrID = *MaybeStrID;
448c5b5cc45SFrancis Visoiu Mistrih   else
449c5b5cc45SFrancis Visoiu Mistrih     return MaybeStrID.takeError();
450c5b5cc45SFrancis Visoiu Mistrih 
4514287c95bSFrancis Visoiu Mistrih   if (Expected<StringRef> Str = (*StrTab)[StrID])
452c5b5cc45SFrancis Visoiu Mistrih     Result = *Str;
453c5b5cc45SFrancis Visoiu Mistrih   else
454c5b5cc45SFrancis Visoiu Mistrih     return Str.takeError();
455c5b5cc45SFrancis Visoiu Mistrih 
456*4aea9f63SKazu Hirata   Result.consume_front("\'");
457*4aea9f63SKazu Hirata   Result.consume_back("\'");
458c5b5cc45SFrancis Visoiu Mistrih 
459c5b5cc45SFrancis Visoiu Mistrih   return Result;
460c5b5cc45SFrancis Visoiu Mistrih }
461