llvm.org GIT mirror llvm / 00c0e00
[Remarks] Simplify and refactor the RemarkParser interface Before, everything was based on some kind of type erased parser implementation which container a lot of boilerplate code when multiple formats were to be supported. This simplifies it by: * the remark now owns its arguments * *always* returning an error from the implementation side * working around the way the YAML parser reports errors: catch them through callbacks and re-insert them in a proper llvm::Error * add a CParser wrapper that is used when implementing the C API to avoid cluttering the C++ API with useless state * LLVMRemarkParserGetNext now returns an object that needs to be released to avoid leaking resources * add a new API to dispose of a remark entry: LLVMRemarkEntryDispose git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@366217 91177308-0d34-0410-b5e6-96231b3b80d8 Francis Visoiu Mistrih a month ago
15 changed file(s) with 519 addition(s) and 527 deletion(s). Raw diff Collapse all Expand all
294294 LLVMRemarkEntryRef Remark = NULL;
295295 while ((Remark = LLVMRemarkParserGetNext(Parser))) {
296296 // use Remark
297 LLVMRemarkEntryDispose(Remark); // Release memory.
297298 }
298299 bool HasError = LLVMRemarkParserHasError(Parser);
299300 LLVMRemarkParserDispose(Parser);
3131 /// The object used to serialize the remarks to a specific format.
3232 std::unique_ptr Serializer;
3333
34 /// Temporary buffer for converting diagnostics into remark objects. This is
35 /// used for the remark arguments that are converted from a vector of
36 /// diagnostic arguments to a vector of remark arguments.
37 SmallVector TmpArgs;
38 /// Convert diagnostics into remark objects. The result uses \p TmpArgs as a
39 /// temporary buffer for the remark arguments, and relies on all the strings
40 /// to be kept in memory until the next call to `toRemark`.
41 /// The lifetime of the members of the result is bound to the lifetime of both
42 /// the remark streamer and the LLVM diagnostics.
34 /// Convert diagnostics into remark objects.
35 /// The lifetime of the members of the result is bound to the lifetime of
36 /// the LLVM diagnostics.
4337 remarks::Remark toRemark(const DiagnosticInfoOptimizationBase &Diag);
4438
4539 public:
8484 Optional Hotness;
8585
8686 /// Arguments collected via the streaming interface.
87 ArrayRef> Args;
87 SmallVector> Args;
88
89 Remark() = default;
90 Remark(Remark &&) = default;
91 Remark &operator=(Remark &&) = default;
8892
8993 /// Return a message composed from the arguments as a string.
9094 std::string getArgsAsMsg() const;
95
96 /// Clone this remark to explicitly ask for a copy.
97 Remark clone() const { return *this; }
98
99 private:
100 /// In order to avoid unwanted copies, "delete" the copy constructor.
101 /// If a copy is needed, it should be done through `Remark::clone()`.
102 Remark(const Remark &) = default;
103 Remark& operator=(const Remark &) = default;
91104 };
92105
93106 // Create wrappers for C Binding types (see CBindingWrapping.h).
2525 struct ParserImpl;
2626 struct ParsedStringTable;
2727
28 class EndOfFileError : public ErrorInfo {
29 public:
30 static char ID;
31
32 EndOfFileError() {}
33
34 void log(raw_ostream &OS) const override { OS << "End of file reached."; }
35 std::error_code convertToErrorCode() const override {
36 return inconvertibleErrorCode();
37 }
38 };
39
2840 /// Parser used to parse a raw buffer to remarks::Remark objects.
2941 struct Parser {
30 /// The hidden implementation of the parser.
31 std::unique_ptr Impl;
42 /// The format of the parser.
43 Format ParserFormat;
3244
33 /// Create a parser parsing \p Buffer to Remark objects.
34 /// This constructor should be only used for parsing remarks without a string
35 /// table.
36 Parser(Format ParserFormat, StringRef Buffer);
45 Parser(Format ParserFormat) : ParserFormat(ParserFormat) {}
3746
38 /// Create a parser parsing \p Buffer to Remark objects, using \p StrTab as a
39 /// string table.
40 Parser(Format ParserFormat, StringRef Buffer,
41 const ParsedStringTable &StrTab);
47 /// If no error occurs, this returns a valid Remark object.
48 /// If an error of type EndOfFileError occurs, it is safe to recover from it
49 /// by stopping the parsing.
50 /// If any other error occurs, it should be propagated to the user.
51 /// The pointer should never be null.
52 virtual Expected> next() = 0;
4253
43 // Needed because ParserImpl is an incomplete type.
44 ~Parser();
45
46 /// Returns an empty Optional if it reached the end.
47 /// Returns a valid remark otherwise.
48 Expected getNext() const;
54 virtual ~Parser() = default;
4955 };
5056
5157 /// In-memory representation of the string table parsed from a buffer (e.g. the
6066 ParsedStringTable(StringRef Buffer);
6167 };
6268
69 Expected>
70 createRemarkParser(Format ParserFormat, StringRef Buf,
71 Optional StrTab = None);
72
6373 } // end namespace remarks
6474 } // end namespace llvm
6575
105105 SourceMgr() = default;
106106 SourceMgr(const SourceMgr &) = delete;
107107 SourceMgr &operator=(const SourceMgr &) = delete;
108 SourceMgr(SourceMgr &&) = default;
109 SourceMgr &operator=(SourceMgr &&) = default;
108110 ~SourceMgr() = default;
109111
110112 void setIncludeDirs(const std::vector &Dirs) {
136136 typedef struct LLVMRemarkOpaqueEntry *LLVMRemarkEntryRef;
137137
138138 /**
139 * Free the resources used by the remark entry.
140 *
141 * \since REMARKS_API_VERSION=0
142 */
143 extern void LLVMRemarkEntryDispose(LLVMRemarkEntryRef Remark);
144
145 /**
139146 * The type of the remark. For example, it can allow users to only keep the
140147 * missed optimizations from the compiler.
141148 *
160167 LLVMRemarkEntryGetRemarkName(LLVMRemarkEntryRef Remark);
161168
162169 /**
163 * Get the name of the function being processsed when the remark was emitted.
170 * Get the name of the function being processed when the remark was emitted.
164171 *
165172 * \since REMARKS_API_VERSION=0
166173 */
198205 *
199206 * If there are no arguments in \p Remark, the return value will be `NULL`.
200207 *
208 * The lifetime of the returned value is bound to the lifetime of \p Remark.
209 *
201210 * \since REMARKS_API_VERSION=0
202211 */
203212 extern LLVMRemarkArgRef LLVMRemarkEntryGetFirstArg(LLVMRemarkEntryRef Remark);
206215 * Get the next argument in \p Remark from the position of \p It.
207216 *
208217 * Returns `NULL` if there are no more arguments available.
218 *
219 * The lifetime of the returned value is bound to the lifetime of \p Remark.
209220 *
210221 * \since REMARKS_API_VERSION=0
211222 */
231242 /**
232243 * Returns the next remark in the file.
233244 *
234 * The value pointed to by the return value is invalidated by the next call to
235 * LLVMRemarkParserGetNext().
245 * The value pointed to by the return value needs to be disposed using a call to
246 * LLVMRemarkEntryDispose().
247 *
248 * All the entries in the returned value that are of LLVMRemarkStringRef type
249 * will become invalidated once a call to LLVMRemarkParserDispose is made.
236250 *
237251 * If the parser reaches the end of the buffer, the return value will be `NULL`.
238252 *
257271 * ```
258272 * LLVMRemarkParserRef Parser = LLVMRemarkParserCreateYAML(Buf, Size);
259273 * LLVMRemarkEntryRef Remark = NULL;
260 * while ((Remark == LLVMRemarkParserGetNext(Parser))) {
274 * while ((Remark = LLVMRemarkParserGetNext(Parser))) {
261275 * // use Remark
276 * LLVMRemarkEntryDispose(Remark); // Release memory.
262277 * }
263278 * bool HasError = LLVMRemarkParserHasError(Parser);
264279 * LLVMRemarkParserDispose(Parser);
7171 /// LLVM Diagnostic -> Remark
7272 remarks::Remark
7373 RemarkStreamer::toRemark(const DiagnosticInfoOptimizationBase &Diag) {
74 // Re-use the buffer.
75 TmpArgs.clear();
76
7774 remarks::Remark R; // The result.
7875 R.RemarkType = toRemarkType(static_cast(Diag.getKind()));
7976 R.PassName = Diag.getPassName();
8380 R.Loc = toRemarkLocation(Diag.getLocation());
8481 R.Hotness = Diag.getHotness();
8582
86 // Use TmpArgs to build the list of arguments and re-use the memory allocated
87 // from previous remark conversions.
8883 for (const DiagnosticInfoOptimizationBase::Argument &Arg : Diag.getArgs()) {
89 TmpArgs.emplace_back();
90 TmpArgs.back().Key = Arg.Key;
91 TmpArgs.back().Val = Arg.Val;
92 TmpArgs.back().Loc = toRemarkLocation(Arg.Loc);
84 R.Args.emplace_back();
85 R.Args.back().Key = Arg.Key;
86 R.Args.back().Val = Arg.Val;
87 R.Args.back().Loc = toRemarkLocation(Arg.Loc);
9388 }
94 R.Args = TmpArgs; // This is valid until the next call to this function.
9589
9690 return R;
9791 }
6565 return nullptr;
6666 }
6767
68 extern "C" void LLVMRemarkEntryDispose(LLVMRemarkEntryRef Remark) {
69 delete unwrap(Remark);
70 }
71
6872 extern "C" LLVMRemarkType LLVMRemarkEntryGetType(LLVMRemarkEntryRef Remark) {
6973 // Assume here that the enums can be converted both ways.
7074 return static_cast(unwrap(Remark)->RemarkType);
1919 using namespace llvm;
2020 using namespace llvm::remarks;
2121
22 static std::unique_ptr formatToParserImpl(Format ParserFormat,
23 StringRef Buf) {
24 switch (ParserFormat) {
25 case Format::YAML:
26 return llvm::make_unique(Buf);
27 case Format::Unknown:
28 llvm_unreachable("Unhandled llvm::remarks::ParserFormat enum");
29 return nullptr;
30 };
31 }
32
33 static std::unique_ptr
34 formatToParserImpl(Format ParserFormat, StringRef Buf,
35 const ParsedStringTable &StrTab) {
36 switch (ParserFormat) {
37 case Format::YAML:
38 return llvm::make_unique(Buf, &StrTab);
39 case Format::Unknown:
40 llvm_unreachable("Unhandled llvm::remarks::ParserFormat enum");
41 return nullptr;
42 };
43 }
44
45 Parser::Parser(Format ParserFormat, StringRef Buf)
46 : Impl(formatToParserImpl(ParserFormat, Buf)) {}
47
48 Parser::Parser(Format ParserFormat, StringRef Buf,
49 const ParsedStringTable &StrTab)
50 : Impl(formatToParserImpl(ParserFormat, Buf, StrTab)) {}
51
52 Parser::~Parser() = default;
53
54 static Expected getNextYAML(YAMLParserImpl &Impl) {
55 YAMLRemarkParser &YAMLParser = Impl.YAMLParser;
56 // Check for EOF.
57 if (Impl.YAMLIt == Impl.YAMLParser.Stream.end())
58 return nullptr;
59
60 auto CurrentIt = Impl.YAMLIt;
61
62 // Try to parse an entry.
63 if (Error E = YAMLParser.parseYAMLElement(*CurrentIt)) {
64 // Set the iterator to the end, in case the user calls getNext again.
65 Impl.YAMLIt = Impl.YAMLParser.Stream.end();
66 return std::move(E);
67 }
68
69 // Move on.
70 ++Impl.YAMLIt;
71
72 // Return the just-parsed remark.
73 if (const Optional &State = YAMLParser.State)
74 return &State->TheRemark;
75 else
76 return createStringError(std::make_error_code(std::errc::invalid_argument),
77 "unexpected error while parsing.");
78 }
79
80 Expected Parser::getNext() const {
81 if (auto *Impl = dyn_cast(this->Impl.get()))
82 return getNextYAML(*Impl);
83 llvm_unreachable("Get next called with an unknown parsing implementation.");
84 }
22 char EndOfFileError::ID = 0;
8523
8624 ParsedStringTable::ParsedStringTable(StringRef InBuffer) : Buffer(InBuffer) {
8725 while (!InBuffer.empty()) {
10846 return StringRef(Buffer.data() + Offset, NextOffset - Offset - 1);
10947 }
11048
49 Expected>
50 llvm::remarks::createRemarkParser(Format ParserFormat, StringRef Buf,
51 Optional StrTab) {
52 switch (ParserFormat) {
53 case Format::YAML:
54 return llvm::make_unique(Buf, StrTab);
55 case Format::Unknown:
56 return createStringError(std::make_error_code(std::errc::invalid_argument),
57 "Unknown remark parser format.");
58 }
59 }
60
61 // Wrapper that holds the state needed to interact with the C API.
62 struct CParser {
63 std::unique_ptr TheParser;
64 Optional Err;
65
66 CParser(Format ParserFormat, StringRef Buf,
67 Optional StrTab = None)
68 : TheParser(cantFail(createRemarkParser(ParserFormat, Buf, StrTab))) {}
69
70 void handleError(Error E) { Err.emplace(toString(std::move(E))); }
71 bool hasError() const { return Err.hasValue(); }
72 const char *getMessage() const { return Err ? Err->c_str() : nullptr; };
73 };
74
11175 // Create wrappers for C Binding types (see CBindingWrapping.h).
112 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(remarks::Parser, LLVMRemarkParserRef)
76 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser, LLVMRemarkParserRef)
11377
11478 extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf,
11579 uint64_t Size) {
116 return wrap(new remarks::Parser(
117 remarks::Format::YAML, StringRef(static_cast(Buf), Size)));
118 }
119
120 static void handleYAMLError(remarks::YAMLParserImpl &Impl, Error E) {
121 handleAllErrors(
122 std::move(E),
123 [&](const YAMLParseError &PE) {
124 Impl.YAMLParser.Stream.printError(&PE.getNode(),
125 Twine(PE.getMessage()) + Twine('\n'));
126 },
127 [&](const ErrorInfoBase &EIB) { EIB.log(Impl.YAMLParser.ErrorStream); });
128 Impl.HasErrors = true;
80 return wrap(new CParser(Format::YAML,
81 StringRef(static_cast(Buf), Size)));
12982 }
13083
13184 extern "C" LLVMRemarkEntryRef
13285 LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) {
133 remarks::Parser &TheParser = *unwrap(Parser);
86 CParser &TheCParser = *unwrap(Parser);
87 remarks::Parser &TheParser = *TheCParser.TheParser;
13488
135 Expected RemarkOrErr = TheParser.getNext();
136 if (!RemarkOrErr) {
137 // Error during parsing.
138 if (auto *Impl = dyn_cast(TheParser.Impl.get()))
139 handleYAMLError(*Impl, RemarkOrErr.takeError());
140 else
141 llvm_unreachable("unkown parser implementation.");
89 Expected> MaybeRemark = TheParser.next();
90 if (Error E = MaybeRemark.takeError()) {
91 if (E.isA()) {
92 consumeError(std::move(E));
93 return nullptr;
94 }
95
96 // Handle the error. Allow it to be checked through HasError and
97 // GetErrorMessage.
98 TheCParser.handleError(std::move(E));
14299 return nullptr;
143100 }
144101
145 if (*RemarkOrErr == nullptr)
146 return nullptr;
147102 // Valid remark.
148 return wrap(*RemarkOrErr);
103 return wrap(MaybeRemark->release());
149104 }
150105
151106 extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) {
152 if (auto *Impl =
153 dyn_cast(unwrap(Parser)->Impl.get()))
154 return Impl->HasErrors;
155 llvm_unreachable("unkown parser implementation.");
107 return unwrap(Parser)->hasError();
156108 }
157109
158110 extern "C" const char *
159111 LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) {
160 if (auto *Impl =
161 dyn_cast(unwrap(Parser)->Impl.get()))
162 return Impl->YAMLParser.ErrorStream.str().c_str();
163 llvm_unreachable("unkown parser implementation.");
112 return unwrap(Parser)->getMessage();
164113 }
165114
166115 extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) {
+0
-33
lib/Remarks/RemarkParserImpl.h less more
None //===-- RemarkParserImpl.h - Implementation details -------------*- C++/-*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file provides implementation details for the remark parser.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_REMARKS_REMARK_PARSER_IMPL_H
13 #define LLVM_REMARKS_REMARK_PARSER_IMPL_H
14
15 #include "llvm/Remarks/RemarkParser.h"
16
17 namespace llvm {
18 namespace remarks {
19 /// This is used as a base for any parser implementation.
20 struct ParserImpl {
21 explicit ParserImpl(Format ParserFormat) : ParserFormat(ParserFormat) {}
22 // Virtual destructor prevents mismatched deletes
23 virtual ~ParserImpl() {}
24
25 // The parser format. This is used as a tag to safely cast between
26 // implementations.
27 Format ParserFormat;
28 };
29 } // end namespace remarks
30 } // end namespace llvm
31
32 #endif /* LLVM_REMARKS_REMARK_PARSER_IMPL_H */
1919
2020 char YAMLParseError::ID = 0;
2121
22 Error YAMLRemarkParser::parseKey(StringRef &Result, yaml::KeyValueNode &Node) {
23 if (auto *Key = dyn_cast(Node.getKey())) {
24 Result = Key->getRawValue();
22 static void handleDiagnostic(const SMDiagnostic &Diag, void *Ctx) {
23 assert(Ctx && "Expected non-null Ctx in diagnostic handler.");
24 std::string &Message = *static_cast(Ctx);
25 assert(Message.empty() && "Expected an empty string.");
26 raw_string_ostream OS(Message);
27 Diag.print(/*ProgName=*/nullptr, OS, /*ShowColors*/ false,
28 /*ShowKindLabels*/ true);
29 OS << '\n';
30 OS.flush();
31 }
32
33 YAMLParseError::YAMLParseError(StringRef Msg, SourceMgr &SM,
34 yaml::Stream &Stream, yaml::Node &Node) {
35 // 1) Set up a diagnostic handler to avoid errors being printed out to
36 // stderr.
37 // 2) Use the stream to print the error with the associated node.
38 // 3) The stream will use the source manager to print the error, which will
39 // call the diagnostic handler.
40 // 4) The diagnostic handler will stream the error directly into this object's
41 // Message member, which is used when logging is asked for.
42 auto OldDiagHandler = SM.getDiagHandler();
43 auto OldDiagCtx = SM.getDiagContext();
44 SM.setDiagHandler(handleDiagnostic, &Message);
45 Stream.printError(&Node, Twine(Msg) + Twine('\n'));
46 // Restore the old handlers.
47 SM.setDiagHandler(OldDiagHandler, OldDiagCtx);
48 }
49
50 static SourceMgr setupSM(std::string &LastErrorMessage) {
51 SourceMgr SM;
52 SM.setDiagHandler(handleDiagnostic, &LastErrorMessage);
53 return SM;
54 }
55
56 YAMLRemarkParser::YAMLRemarkParser(StringRef Buf,
57 Optional StrTab)
58 : Parser{Format::YAML}, StrTab(StrTab), LastErrorMessage(),
59 SM(setupSM(LastErrorMessage)), Stream(Buf, SM), YAMLIt(Stream.begin()) {}
60
61 Error YAMLRemarkParser::error(StringRef Message, yaml::Node &Node) {
62 return make_error(Message, SM, Stream, Node);
63 }
64
65 Error YAMLRemarkParser::error() {
66 if (LastErrorMessage.empty())
2567 return Error::success();
26 }
27
28 return make_error("key is not a string.", Node);
29 }
30
31 template
32 Error YAMLRemarkParser::parseStr(T &Result, yaml::KeyValueNode &Node) {
33 auto *Value = dyn_cast(Node.getValue());
34 if (!Value)
35 return make_error("expected a value of scalar type.", Node);
36 StringRef Tmp;
37 if (!StrTab) {
38 Tmp = Value->getRawValue();
39 } else {
40 // If we have a string table, parse it as an unsigned.
41 unsigned StrID = 0;
42 if (Error E = parseUnsigned(StrID, Node))
43 return E;
44 if (Expected Str = (**StrTab)[StrID])
45 Tmp = *Str;
46 else
47 return Str.takeError();
48 }
49
50 if (Tmp.front() == '\'')
51 Tmp = Tmp.drop_front();
52
53 if (Tmp.back() == '\'')
54 Tmp = Tmp.drop_back();
55
56 Result = Tmp;
57
58 return Error::success();
59 }
60
61 template
62 Error YAMLRemarkParser::parseUnsigned(T &Result, yaml::KeyValueNode &Node) {
63 SmallVector Tmp;
64 auto *Value = dyn_cast(Node.getValue());
65 if (!Value)
66 return make_error("expected a value of scalar type.", Node);
67 unsigned UnsignedValue = 0;
68 if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue))
69 return make_error("expected a value of integer type.",
70 *Value);
71 Result = UnsignedValue;
72 return Error::success();
73 }
74
75 Error YAMLRemarkParser::parseType(Type &Result, yaml::MappingNode &Node) {
68 Error E = make_error(LastErrorMessage);
69 LastErrorMessage.clear();
70 return E;
71 }
72
73 Expected>
74 YAMLRemarkParser::parseRemark(yaml::Document &RemarkEntry) {
75 if (Error E = error())
76 return std::move(E);
77
78 yaml::Node *YAMLRoot = RemarkEntry.getRoot();
79 if (!YAMLRoot) {
80 return createStringError(std::make_error_code(std::errc::invalid_argument),
81 "not a valid YAML file.");
82 }
83
84 auto *Root = dyn_cast(YAMLRoot);
85 if (!Root)
86 return error("document root is not of mapping type.", *YAMLRoot);
87
88 std::unique_ptr Result = llvm::make_unique();
89 Remark &TheRemark = *Result;
90
91 // First, the type. It needs special handling since is not part of the
92 // key-value stream.
93 Expected T = parseType(*Root);
94 if (!T)
95 return T.takeError();
96 else
97 TheRemark.RemarkType = *T;
98
99 // Then, parse the fields, one by one.
100 for (yaml::KeyValueNode &RemarkField : *Root) {
101 Expected MaybeKey = parseKey(RemarkField);
102 if (!MaybeKey)
103 return MaybeKey.takeError();
104 StringRef KeyName = *MaybeKey;
105
106 if (KeyName == "Pass") {
107 if (Expected MaybeStr = parseStr(RemarkField))
108 TheRemark.PassName = *MaybeStr;
109 else
110 return MaybeStr.takeError();
111 } else if (KeyName == "Name") {
112 if (Expected MaybeStr = parseStr(RemarkField))
113 TheRemark.RemarkName = *MaybeStr;
114 else
115 return MaybeStr.takeError();
116 } else if (KeyName == "Function") {
117 if (Expected MaybeStr = parseStr(RemarkField))
118 TheRemark.FunctionName = *MaybeStr;
119 else
120 return MaybeStr.takeError();
121 } else if (KeyName == "Hotness") {
122 if (Expected MaybeU = parseUnsigned(RemarkField))
123 TheRemark.Hotness = *MaybeU;
124 else
125 return MaybeU.takeError();
126 } else if (KeyName == "DebugLoc") {
127 if (Expected MaybeLoc = parseDebugLoc(RemarkField))
128 TheRemark.Loc = *MaybeLoc;
129 else
130 return MaybeLoc.takeError();
131 } else if (KeyName == "Args") {
132 auto *Args = dyn_cast(RemarkField.getValue());
133 if (!Args)
134 return error("wrong value type for key.", RemarkField);
135
136 for (yaml::Node &Arg : *Args) {
137 if (Expected MaybeArg = parseArg(Arg))
138 TheRemark.Args.push_back(*MaybeArg);
139 else
140 return MaybeArg.takeError();
141 }
142 } else {
143 return error("unknown key.", RemarkField);
144 }
145 }
146
147 // Check if any of the mandatory fields are missing.
148 if (TheRemark.RemarkType == Type::Unknown || TheRemark.PassName.empty() ||
149 TheRemark.RemarkName.empty() || TheRemark.FunctionName.empty())
150 return error("Type, Pass, Name or Function missing.",
151 *RemarkEntry.getRoot());
152
153 return std::move(Result);
154 }
155
156 Expected YAMLRemarkParser::parseType(yaml::MappingNode &Node) {
76157 auto Type = StringSwitch(Node.getRawTag())
77158 .Case("!Passed", remarks::Type::Passed)
78159 .Case("!Missed", remarks::Type::Missed)
82163 .Case("!Failure", remarks::Type::Failure)
83164 .Default(remarks::Type::Unknown);
84165 if (Type == remarks::Type::Unknown)
85 return make_error("expected a remark tag.", Node);
86 Result = Type;
87 return Error::success();
88 }
89
90 Error YAMLRemarkParser::parseDebugLoc(Optional &Result,
91 yaml::KeyValueNode &Node) {
166 return error("expected a remark tag.", Node);
167 return Type;
168 }
169
170 Expected YAMLRemarkParser::parseKey(yaml::KeyValueNode &Node) {
171 if (auto *Key = dyn_cast(Node.getKey()))
172 return Key->getRawValue();
173
174 return error("key is not a string.", Node);
175 }
176
177 Expected YAMLRemarkParser::parseStr(yaml::KeyValueNode &Node) {
178 auto *Value = dyn_cast(Node.getValue());
179 if (!Value)
180 return error("expected a value of scalar type.", Node);
181 StringRef Result;
182 if (!StrTab) {
183 Result = Value->getRawValue();
184 } else {
185 // If we have a string table, parse it as an unsigned.
186 unsigned StrID = 0;
187 if (Expected MaybeStrID = parseUnsigned(Node))
188 StrID = *MaybeStrID;
189 else
190 return MaybeStrID.takeError();
191
192 if (Expected Str = (**StrTab)[StrID])
193 Result = *Str;
194 else
195 return Str.takeError();
196 }
197
198 if (Result.front() == '\'')
199 Result = Result.drop_front();
200
201 if (Result.back() == '\'')
202 Result = Result.drop_back();
203
204 return Result;
205 }
206
207 Expected YAMLRemarkParser::parseUnsigned(yaml::KeyValueNode &Node) {
208 SmallVector Tmp;
209 auto *Value = dyn_cast(Node.getValue());
210 if (!Value)
211 return error("expected a value of scalar type.", Node);
212 unsigned UnsignedValue = 0;
213 if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue))
214 return error("expected a value of integer type.", *Value);
215 return UnsignedValue;
216 }
217
218 Expected
219 YAMLRemarkParser::parseDebugLoc(yaml::KeyValueNode &Node) {
92220 auto *DebugLoc = dyn_cast(Node.getValue());
93221 if (!DebugLoc)
94 return make_error("expected a value of mapping type.",
95 Node);
222 return error("expected a value of mapping type.", Node);
96223
97224 Optional File;
98225 Optional Line;
99226 Optional Column;
100227
101228 for (yaml::KeyValueNode &DLNode : *DebugLoc) {
102 StringRef KeyName;
103 if (Error E = parseKey(KeyName, DLNode))
104 return E;
229 Expected MaybeKey = parseKey(DLNode);
230 if (!MaybeKey)
231 return MaybeKey.takeError();
232 StringRef KeyName = *MaybeKey;
233
105234 if (KeyName == "File") {
106 if (Error E = parseStr(File, DLNode))
107 return E;
235 if (Expected MaybeStr = parseStr(DLNode))
236 File = *MaybeStr;
237 else
238 return MaybeStr.takeError();
108239 } else if (KeyName == "Column") {
109 if (Error E = parseUnsigned(Column, DLNode))
110 return E;
240 if (Expected MaybeU = parseUnsigned(DLNode))
241 Column = *MaybeU;
242 else
243 return MaybeU.takeError();
111244 } else if (KeyName == "Line") {
112 if (Error E = parseUnsigned(Line, DLNode))
113 return E;
245 if (Expected MaybeU = parseUnsigned(DLNode))
246 Line = *MaybeU;
247 else
248 return MaybeU.takeError();
114249 } else {
115 return make_error("unknown entry in DebugLoc map.",
116 DLNode);
250 return error("unknown entry in DebugLoc map.", DLNode);
117251 }
118252 }
119253
120254 // If any of the debug loc fields is missing, return an error.
121255 if (!File || !Line || !Column)
122 return make_error("DebugLoc node incomplete.", Node);
123
124 Result = RemarkLocation{*File, *Line, *Column};
125
126 return Error::success();
127 }
128
129 Error YAMLRemarkParser::parseRemarkField(yaml::KeyValueNode &RemarkField) {
130
131 StringRef KeyName;
132 if (Error E = parseKey(KeyName, RemarkField))
133 return E;
134
135 if (KeyName == "Pass") {
136 if (Error E = parseStr(State->TheRemark.PassName, RemarkField))
137 return E;
138 } else if (KeyName == "Name") {
139 if (Error E = parseStr(State->TheRemark.RemarkName, RemarkField))
140 return E;
141 } else if (KeyName == "Function") {
142 if (Error E = parseStr(State->TheRemark.FunctionName, RemarkField))
143 return E;
144 } else if (KeyName == "Hotness") {
145 State->TheRemark.Hotness = 0;
146 if (Error E = parseUnsigned(*State->TheRemark.Hotness, RemarkField))
147 return E;
148 } else if (KeyName == "DebugLoc") {
149 if (Error E = parseDebugLoc(State->TheRemark.Loc, RemarkField))
150 return E;
151 } else if (KeyName == "Args") {
152 auto *Args = dyn_cast(RemarkField.getValue());
153 if (!Args)
154 return make_error("wrong value type for key.",
155 RemarkField);
156
157 for (yaml::Node &Arg : *Args)
158 if (Error E = parseArg(State->Args, Arg))
159 return E;
160
161 State->TheRemark.Args = State->Args;
162 } else {
163 return make_error("unknown key.", RemarkField);
164 }
165
166 return Error::success();
167 }
168
169 Error YAMLRemarkParser::parseArg(SmallVectorImpl &Args,
170 yaml::Node &Node) {
256 return error("DebugLoc node incomplete.", Node);
257
258 return RemarkLocation{*File, *Line, *Column};
259 }
260
261 Expected YAMLRemarkParser::parseArg(yaml::Node &Node) {
171262 auto *ArgMap = dyn_cast(&Node);
172263 if (!ArgMap)
173 return make_error("expected a value of mapping type.",
174 Node);
175
176 StringRef KeyStr;
177 StringRef ValueStr;
264 return error("expected a value of mapping type.", Node);
265
266 Optional KeyStr;
267 Optional ValueStr;
178268 Optional Loc;
179269
180 for (yaml::KeyValueNode &ArgEntry : *ArgMap)
181 if (Error E = parseArgEntry(ArgEntry, KeyStr, ValueStr, Loc))
182 return E;
183
184 if (KeyStr.empty())
185 return make_error("argument key is missing.", *ArgMap);
186 if (ValueStr.empty())
187 return make_error("argument value is missing.", *ArgMap);
188
189 Args.push_back(Argument{KeyStr, ValueStr, Loc});
190
191 return Error::success();
192 }
193
194 Error YAMLRemarkParser::parseArgEntry(yaml::KeyValueNode &ArgEntry,
195 StringRef &KeyStr, StringRef &ValueStr,
196 Optional &Loc) {
197 StringRef KeyName;
198 if (Error E = parseKey(KeyName, ArgEntry))
199 return E;
200
201 // Try to parse debug locs.
202 if (KeyName == "DebugLoc") {
203 // Can't have multiple DebugLoc entries per argument.
204 if (Loc)
205 return make_error(
206 "only one DebugLoc entry is allowed per argument.", ArgEntry);
207
208 if (Error E = parseDebugLoc(Loc, ArgEntry))
209 return E;
210 return Error::success();
211 }
212
213 // If we already have a string, error out.
214 if (!ValueStr.empty())
215 return make_error(
216 "only one string entry is allowed per argument.", ArgEntry);
217
218 // Try to parse a string.
219 if (Error E = parseStr(ValueStr, ArgEntry))
220 return E;
221
222 // Keep the key from the string.
223 KeyStr = KeyName;
224 return Error::success();
225 }
226
227 Error YAMLRemarkParser::parseYAMLElement(yaml::Document &Remark) {
228 // Parsing a new remark, clear the previous one by re-constructing the state
229 // in-place in the Optional.
230 State.emplace(TmpArgs);
231
232 yaml::Node *YAMLRoot = Remark.getRoot();
233 if (!YAMLRoot)
234 return createStringError(std::make_error_code(std::errc::invalid_argument),
235 "not a valid YAML file.");
236
237 auto *Root = dyn_cast(YAMLRoot);
238 if (!Root)
239 return make_error("document root is not of mapping type.",
240 *YAMLRoot);
241
242 if (Error E = parseType(State->TheRemark.RemarkType, *Root))
243 return E;
244
245 for (yaml::KeyValueNode &RemarkField : *Root)
246 if (Error E = parseRemarkField(RemarkField))
247 return E;
248
249 // If the YAML parsing failed, don't even continue parsing. We might
250 // encounter malformed YAML.
251 if (Stream.failed())
252 return make_error("YAML parsing failed.",
253 *Remark.getRoot());
254
255 // Check if any of the mandatory fields are missing.
256 if (State->TheRemark.RemarkType == Type::Unknown ||
257 State->TheRemark.PassName.empty() ||
258 State->TheRemark.RemarkName.empty() ||
259 State->TheRemark.FunctionName.empty())
260 return make_error("Type, Pass, Name or Function missing.",
261 *Remark.getRoot());
262
263 return Error::success();
264 }
265
266 /// Handle a diagnostic from the YAML stream. Records the error in the
267 /// YAMLRemarkParser class.
268 void YAMLRemarkParser::HandleDiagnostic(const SMDiagnostic &Diag, void *Ctx) {
269 assert(Ctx && "Expected non-null Ctx in diagnostic handler.");
270 auto *Parser = static_cast(Ctx);
271 Diag.print(/*ProgName=*/nullptr, Parser->ErrorStream, /*ShowColors*/ false,
272 /*ShowKindLabels*/ true);
273 }
270 for (yaml::KeyValueNode &ArgEntry : *ArgMap) {
271 Expected MaybeKey = parseKey(ArgEntry);
272 if (!MaybeKey)
273 return MaybeKey.takeError();
274 StringRef KeyName = *MaybeKey;
275
276 // Try to parse debug locs.
277 if (KeyName == "DebugLoc") {
278 // Can't have multiple DebugLoc entries per argument.
279 if (Loc)
280 return error("only one DebugLoc entry is allowed per argument.",
281 ArgEntry);
282
283 if (Expected MaybeLoc = parseDebugLoc(ArgEntry)) {
284 Loc = *MaybeLoc;
285 continue;
286 } else
287 return MaybeLoc.takeError();
288 }
289
290 // If we already have a string, error out.
291 if (ValueStr)
292 return error("only one string entry is allowed per argument.", ArgEntry);
293
294 // Try to parse the value.
295 if (Expected MaybeStr = parseStr(ArgEntry))
296 ValueStr = *MaybeStr;
297 else
298 return MaybeStr.takeError();
299
300 // Keep the key from the string.
301 KeyStr = KeyName;
302 }
303
304 if (!KeyStr)
305 return error("argument key is missing.", *ArgMap);
306 if (!ValueStr)
307 return error("argument value is missing.", *ArgMap);
308
309 return Argument{*KeyStr, *ValueStr, Loc};
310 }
311
312 Expected> YAMLRemarkParser::next() {
313 if (YAMLIt == Stream.end())
314 return make_error();
315
316 Expected> MaybeResult = parseRemark(*YAMLIt);
317 if (!MaybeResult) {
318 // Avoid garbage input, set the iterator to the end.
319 YAMLIt = Stream.end();
320 return MaybeResult.takeError();
321 }
322
323 ++YAMLIt;
324
325 return std::move(*MaybeResult);
326 }
1212 #ifndef LLVM_REMARKS_YAML_REMARK_PARSER_H
1313 #define LLVM_REMARKS_YAML_REMARK_PARSER_H
1414
15 #include "RemarkParserImpl.h"
1615 #include "llvm/ADT/Optional.h"
1716 #include "llvm/ADT/SmallVector.h"
1817 #include "llvm/Remarks/Remark.h"
2625
2726 namespace llvm {
2827 namespace remarks {
29 /// Parses and holds the state of the latest parsed remark.
30 struct YAMLRemarkParser {
31 /// Source manager for better error messages.
32 SourceMgr SM;
33 /// Stream for yaml parsing.
34 yaml::Stream Stream;
35 /// Storage for the error stream.
36 std::string ErrorString;
37 /// The error stream.
38 raw_string_ostream ErrorStream;
39 /// Temporary parsing buffer for the arguments.
40 SmallVector TmpArgs;
41 /// The string table used for parsing strings.
42 Optional StrTab;
43 /// The state used by the parser to parse a remark entry. Invalidated with
44 /// every call to `parseYAMLElement`.
45 struct ParseState {
46 /// Temporary parsing buffer for the arguments.
47 /// The parser itself is owning this buffer in order to reduce the number of
48 /// allocations.
49 SmallVectorImpl &Args;
50 Remark TheRemark;
51
52 ParseState(SmallVectorImpl &Args) : Args(Args) {}
53 /// Use Args only as a **temporary** buffer.
54 ~ParseState() { Args.clear(); }
55 };
56
57 /// The current state of the parser. If the parsing didn't start yet, it will
58 /// not be containing any value.
59 Optional State;
60
61 YAMLRemarkParser(StringRef Buf,
62 Optional StrTab = None)
63 : SM(), Stream(Buf, SM), ErrorString(), ErrorStream(ErrorString),
64 TmpArgs(), StrTab(StrTab) {
65 SM.setDiagHandler(YAMLRemarkParser::HandleDiagnostic, this);
66 }
67
68 /// Parse a YAML element.
69 Error parseYAMLElement(yaml::Document &Remark);
70
71 private:
72 /// Parse one key to a string.
73 /// otherwise.
74 Error parseKey(StringRef &Result, yaml::KeyValueNode &Node);
75 /// Parse one value to a string.
76 template Error parseStr(T &Result, yaml::KeyValueNode &Node);
77 /// Parse one value to an unsigned.
78 template
79 Error parseUnsigned(T &Result, yaml::KeyValueNode &Node);
80 /// Parse the type of a remark to an enum type.
81 Error parseType(Type &Result, yaml::MappingNode &Node);
82 /// Parse a debug location.
83 Error parseDebugLoc(Optional &Result,
84 yaml::KeyValueNode &Node);
85 /// Parse a remark field and update the parsing state.
86 Error parseRemarkField(yaml::KeyValueNode &RemarkField);
87 /// Parse an argument.
88 Error parseArg(SmallVectorImpl &TmpArgs, yaml::Node &Node);
89 /// Parse an entry from the contents of an argument.
90 Error parseArgEntry(yaml::KeyValueNode &ArgEntry, StringRef &KeyStr,
91 StringRef &ValueStr, Optional &Loc);
92
93 /// Handle a diagnostic from the YAML stream. Records the error in the
94 /// YAMLRemarkParser class.
95 static void HandleDiagnostic(const SMDiagnostic &Diag, void *Ctx);
96 };
9728
9829 class YAMLParseError : public ErrorInfo {
9930 public:
10031 static char ID;
10132
102 YAMLParseError(StringRef Message, yaml::Node &Node)
103 : Message(Message), Node(Node) {}
33 YAMLParseError(StringRef Message, SourceMgr &SM, yaml::Stream &Stream,
34 yaml::Node &Node);
35
36 YAMLParseError(StringRef Message) : Message(Message) {}
10437
10538 void log(raw_ostream &OS) const override { OS << Message; }
10639 std::error_code convertToErrorCode() const override {
10740 return inconvertibleErrorCode();
10841 }
10942
110 StringRef getMessage() const { return Message; }
111 yaml::Node &getNode() const { return Node; }
112
11343 private:
114 StringRef Message; // No need to hold a full copy of the buffer.
115 yaml::Node &Node;
44 std::string Message;
11645 };
11746
11847 /// Regular YAML to Remark parser.
119 struct YAMLParserImpl : public ParserImpl {
120 /// The object parsing the YAML.
121 YAMLRemarkParser YAMLParser;
48 struct YAMLRemarkParser : public Parser {
49 /// The string table used for parsing strings.
50 Optional StrTab;
51 /// Last error message that can come from the YAML parser diagnostics.
52 /// We need this for catching errors in the constructor.
53 std::string LastErrorMessage;
54 /// Source manager for better error messages.
55 SourceMgr SM;
56 /// Stream for yaml parsing.
57 yaml::Stream Stream;
12258 /// Iterator in the YAML stream.
12359 yaml::document_iterator YAMLIt;
124 /// Set to `true` if we had any errors during parsing.
125 bool HasErrors = false;
12660
127 YAMLParserImpl(StringRef Buf,
128 Optional StrTab = None)
129 : ParserImpl{Format::YAML}, YAMLParser(Buf, StrTab),
130 YAMLIt(YAMLParser.Stream.begin()), HasErrors(false) {}
61 YAMLRemarkParser(StringRef Buf,
62 Optional StrTab = None);
13163
132 static bool classof(const ParserImpl *PI) {
133 return PI->ParserFormat == Format::YAML;
64 Expected> next() override;
65
66 static bool classof(const Parser *P) {
67 return P->ParserFormat == Format::YAML;
13468 }
69
70 private:
71 /// Create a YAMLParseError error from an existing error generated by the YAML
72 /// parser.
73 /// If there is no error, this returns Success.
74 Error error();
75 /// Create a YAMLParseError error referencing a specific node.
76 Error error(StringRef Message, yaml::Node &Node);
77 /// Parse a YAML remark to a remarks::Remark object.
78 Expected> parseRemark(yaml::Document &Remark);
79 /// Parse the type of a remark to an enum type.
80 Expected parseType(yaml::MappingNode &Node);
81 /// Parse one key to a string.
82 Expected parseKey(yaml::KeyValueNode &Node);
83 /// Parse one value to a string.
84 Expected parseStr(yaml::KeyValueNode &Node);
85 /// Parse one value to an unsigned.
86 Expected parseUnsigned(yaml::KeyValueNode &Node);
87 /// Parse a debug location.
88 Expected parseDebugLoc(yaml::KeyValueNode &Node);
89 /// Parse an argument.
90 Expected parseArg(yaml::Node &Node);
13591 };
13692 } // end namespace remarks
13793 } // end namespace llvm
149149 return false;
150150 }
151151
152 remarks::Parser Parser(remarks::Format::YAML, (*Buf)->getBuffer());
152 Expected> MaybeParser =
153 remarks::createRemarkParser(remarks::Format::YAML, (*Buf)->getBuffer());
154 if (!MaybeParser) {
155 handleAllErrors(MaybeParser.takeError(), [&](const ErrorInfoBase &PE) {
156 PE.log(WithColor::error());
157 });
158 return false;
159 }
160 remarks::Parser &Parser = **MaybeParser;
153161
154162 while (true) {
155 Expected RemarkOrErr = Parser.getNext();
156 if (!RemarkOrErr) {
157 handleAllErrors(RemarkOrErr.takeError(), [&](const ErrorInfoBase &PE) {
163 Expected> MaybeRemark = Parser.next();
164 if (!MaybeRemark) {
165 Error E = MaybeRemark.takeError();
166 if (E.isA()) {
167 // EOF.
168 consumeError(std::move(E));
169 break;
170 }
171 handleAllErrors(MaybeRemark.takeError(), [&](const ErrorInfoBase &PE) {
158172 PE.log(WithColor::error());
159173 });
160174 return false;
161175 }
162 if (!*RemarkOrErr) // End of file.
163 break;
164
165 const remarks::Remark &Remark = **RemarkOrErr;
176
177 const remarks::Remark &Remark = **MaybeRemark;
166178
167179 bool Transformed = Remark.RemarkType == remarks::Type::Passed;
168180
55 LLVMRemarkArgGetKey
66 LLVMRemarkArgGetValue
77 LLVMRemarkArgGetDebugLoc
8 LLVMRemarkEntryDispose
89 LLVMRemarkEntryGetType
910 LLVMRemarkEntryGetPassName
1011 LLVMRemarkEntryGetRemarkName
1313 using namespace llvm;
1414
1515 template void parseGood(const char (&Buf)[N]) {
16 remarks::Parser Parser(remarks::Format::YAML, {Buf, N - 1});
17 Expected<const remarks::Remark *> Remark = Parser.getNext();
16 Expected<std::unique_ptr> MaybeParser =
17 remarks::createRemarkParser(remarks::Format::YAML, {Buf, N - 1});
18 EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
19 EXPECT_TRUE(*MaybeParser != nullptr);
20
21 remarks::Parser &Parser = **MaybeParser;
22 Expected> Remark = Parser.next();
1823 EXPECT_FALSE(errorToBool(Remark.takeError())); // Check for parsing errors.
1924 EXPECT_TRUE(*Remark != nullptr); // At least one remark.
20 Remark = Parser.getNext();
21 EXPECT_FALSE(errorToBool(Remark.takeError())); // Check for parsing errors.
22 EXPECT_TRUE(*Remark == nullptr); // Check that there are no more remarks.
25 Remark = Parser.next();
26 Error E = Remark.takeError();
27 EXPECT_TRUE(E.isA());
28 EXPECT_TRUE(errorToBool(std::move(E))); // Check for parsing errors.
2329 }
2430
2531 template
2632 bool parseExpectError(const char (&Buf)[N], const char *Error) {
27 remarks::Parser Parser(remarks::Format::YAML, {Buf, N - 1});
28 Expected Remark = Parser.getNext();
29 EXPECT_FALSE(Remark); // Expect an error here.
33 Expected> MaybeParser =
34 remarks::createRemarkParser(remarks::Format::YAML, {Buf, N - 1});
35 EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
36 EXPECT_TRUE(*MaybeParser != nullptr);
37
38 remarks::Parser &Parser = **MaybeParser;
39 Expected> Remark = Parser.next();
40 EXPECT_FALSE(Remark); // Check for parsing errors.
3041
3142 std::string ErrorStr;
3243 raw_string_ostream Stream(ErrorStr);
4152
4253 TEST(YAMLRemarks, ParsingNotYAML) {
4354 EXPECT_TRUE(
44 parseExpectError("\x01\x02\x03\x04\x05\x06", "not a valid YAML file."));
55 parseExpectError("\x01\x02\x03\x04\x05\x06", "Got empty plain scalar"));
4556 }
4657
4758 TEST(YAMLRemarks, ParsingGood) {
314325 "Name: NoDefinition\n"
315326 "Function: foo\n"
316327 "Args:\n"
317 " - Callee: ''\n"
318 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
319 "",
320 "argument value is missing."));
321 // No arg value.
322 EXPECT_TRUE(parseExpectError("\n"
323 "--- !Missed\n"
324 "Pass: inline\n"
325 "Name: NoDefinition\n"
326 "Function: foo\n"
327 "Args:\n"
328328 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
329329 "",
330330 "argument key is missing."));
353353 " - String: ' because its definition is unavailable'\n"
354354 "\n";
355355
356 remarks::Parser Parser(remarks::Format::YAML, Buf);
357 Expected RemarkOrErr = Parser.getNext();
358 EXPECT_FALSE(errorToBool(RemarkOrErr.takeError()));
359 EXPECT_TRUE(*RemarkOrErr != nullptr);
360
361 const remarks::Remark &Remark = **RemarkOrErr;
356 Expected> MaybeParser =
357 remarks::createRemarkParser(remarks::Format::YAML, Buf);
358 EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
359 EXPECT_TRUE(*MaybeParser != nullptr);
360
361 remarks::Parser &Parser = **MaybeParser;
362 Expected> MaybeRemark = Parser.next();
363 EXPECT_FALSE(
364 errorToBool(MaybeRemark.takeError())); // Check for parsing errors.
365 EXPECT_TRUE(*MaybeRemark != nullptr); // At least one remark.
366
367 const remarks::Remark &Remark = **MaybeRemark;
362368 EXPECT_EQ(Remark.RemarkType, remarks::Type::Missed);
363369 EXPECT_EQ(checkStr(Remark.PassName, 6), "inline");
364370 EXPECT_EQ(checkStr(Remark.RemarkName, 12), "NoDefinition");
407413 ++ArgID;
408414 }
409415
410 RemarkOrErr = Parser.getNext();
411 EXPECT_FALSE(errorToBool(RemarkOrErr.takeError()));
412 EXPECT_EQ(*RemarkOrErr, nullptr);
416 MaybeRemark = Parser.next();
417 Error E = MaybeRemark.takeError();
418 EXPECT_TRUE(E.isA());
419 EXPECT_TRUE(errorToBool(std::move(E))); // Check for parsing errors.
413420 }
414421
415422 static inline StringRef checkStr(LLVMRemarkStringRef Str,
485492 }
486493 ++ArgID;
487494 } while ((Arg = LLVMRemarkEntryGetNextArg(Arg, Remark)));
495
496 LLVMRemarkEntryDispose(Remark);
488497
489498 EXPECT_EQ(LLVMRemarkParserGetNext(Parser), nullptr);
490499
515524 115);
516525
517526 remarks::ParsedStringTable StrTab(StrTabBuf);
518 remarks::Parser Parser(remarks::Format::YAML, Buf, StrTab);
519 Expected RemarkOrErr = Parser.getNext();
520 EXPECT_FALSE(errorToBool(RemarkOrErr.takeError()));
521 EXPECT_TRUE(*RemarkOrErr != nullptr);
522
523 const remarks::Remark &Remark = **RemarkOrErr;
527 Expected> MaybeParser =
528 remarks::createRemarkParser(remarks::Format::YAML, Buf, &StrTab);
529 EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
530 EXPECT_TRUE(*MaybeParser != nullptr);
531
532 remarks::Parser &Parser = **MaybeParser;
533 Expected> MaybeRemark = Parser.next();
534 EXPECT_FALSE(
535 errorToBool(MaybeRemark.takeError())); // Check for parsing errors.
536 EXPECT_TRUE(*MaybeRemark != nullptr); // At least one remark.
537
538 const remarks::Remark &Remark = **MaybeRemark;
524539 EXPECT_EQ(Remark.RemarkType, remarks::Type::Missed);
525540 EXPECT_EQ(checkStr(Remark.PassName, 6), "inline");
526541 EXPECT_EQ(checkStr(Remark.RemarkName, 12), "NoDefinition");
569584 ++ArgID;
570585 }
571586
572 RemarkOrErr = Parser.getNext();
573 EXPECT_FALSE(errorToBool(RemarkOrErr.takeError()));
574 EXPECT_EQ(*RemarkOrErr, nullptr);
587 MaybeRemark = Parser.next();
588 Error E = MaybeRemark.takeError();
589 EXPECT_TRUE(E.isA());
590 EXPECT_TRUE(errorToBool(std::move(E))); // Check for parsing errors.
575591 }
576592
577593 TEST(YAMLRemarks, ParsingBadStringTableIndex) {
583599 StringRef StrTabBuf = StringRef("inline");
584600
585601 remarks::ParsedStringTable StrTab(StrTabBuf);
586 remarks::Parser Parser(remarks::Format::YAML, Buf, StrTab);
587 Expected Remark = Parser.getNext();
588 EXPECT_FALSE(Remark); // Expect an error here.
602 Expected> MaybeParser =
603 remarks::createRemarkParser(remarks::Format::YAML, Buf, &StrTab);
604 EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
605 EXPECT_TRUE(*MaybeParser != nullptr);
606
607 remarks::Parser &Parser = **MaybeParser;
608 Expected> MaybeRemark = Parser.next();
609 EXPECT_FALSE(MaybeRemark); // Expect an error here.
589610
590611 std::string ErrorStr;
591612 raw_string_ostream Stream(ErrorStr);
592 handleAllErrors(Remark.takeError(),
613 handleAllErrors(MaybeRemark.takeError(),
593614 [&](const ErrorInfoBase &EIB) { EIB.log(Stream); });
594615 EXPECT_TRUE(
595616 StringRef(Stream.str())