1 //===- unittest/Support/YAMLRemarksParsingTest.cpp - OptTable tests -------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm-c/Remarks.h"
10 #include "llvm/Remarks/Remark.h"
11 #include "llvm/Remarks/RemarkParser.h"
12 #include "gtest/gtest.h"
13
14 using namespace llvm;
15
parseGood(const char (& Buf)[N])16 template <size_t N> void parseGood(const char (&Buf)[N]) {
17 Expected<std::unique_ptr<remarks::RemarkParser>> MaybeParser =
18 remarks::createRemarkParser(remarks::Format::YAML, {Buf, N - 1});
19 EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
20 EXPECT_TRUE(*MaybeParser != nullptr);
21
22 remarks::RemarkParser &Parser = **MaybeParser;
23 Expected<std::unique_ptr<remarks::Remark>> Remark = Parser.next();
24 EXPECT_FALSE(errorToBool(Remark.takeError())); // Check for parsing errors.
25 EXPECT_TRUE(*Remark != nullptr); // At least one remark.
26 Remark = Parser.next();
27 Error E = Remark.takeError();
28 EXPECT_TRUE(E.isA<remarks::EndOfFileError>());
29 EXPECT_TRUE(errorToBool(std::move(E))); // Check for parsing errors.
30 }
31
parseGoodMeta(StringRef Buf)32 void parseGoodMeta(StringRef Buf) {
33 Expected<std::unique_ptr<remarks::RemarkParser>> MaybeParser =
34 remarks::createRemarkParserFromMeta(remarks::Format::YAML, Buf);
35 EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
36 EXPECT_TRUE(*MaybeParser != nullptr);
37
38 remarks::RemarkParser &Parser = **MaybeParser;
39 Expected<std::unique_ptr<remarks::Remark>> Remark = Parser.next();
40 EXPECT_FALSE(errorToBool(Remark.takeError())); // Check for parsing errors.
41 EXPECT_TRUE(*Remark != nullptr); // At least one remark.
42 Remark = Parser.next();
43 Error E = Remark.takeError();
44 EXPECT_TRUE(E.isA<remarks::EndOfFileError>());
45 EXPECT_TRUE(errorToBool(std::move(E))); // Check for parsing errors.
46 }
47
48 template <size_t N>
parseExpectError(const char (& Buf)[N],const char * Error)49 bool parseExpectError(const char (&Buf)[N], const char *Error) {
50 Expected<std::unique_ptr<remarks::RemarkParser>> MaybeParser =
51 remarks::createRemarkParser(remarks::Format::YAML, {Buf, N - 1});
52 EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
53 EXPECT_TRUE(*MaybeParser != nullptr);
54
55 remarks::RemarkParser &Parser = **MaybeParser;
56 Expected<std::unique_ptr<remarks::Remark>> Remark = Parser.next();
57 EXPECT_FALSE(Remark); // Check for parsing errors.
58
59 std::string ErrorStr;
60 raw_string_ostream Stream(ErrorStr);
61 handleAllErrors(Remark.takeError(),
62 [&](const ErrorInfoBase &EIB) { EIB.log(Stream); });
63 return StringRef(Stream.str()).contains(Error);
64 }
65
66 enum class CmpType {
67 Equal,
68 Contains
69 };
70
parseExpectErrorMeta(StringRef Buf,const char * Error,CmpType Cmp,Optional<StringRef> ExternalFilePrependPath=None)71 void parseExpectErrorMeta(StringRef Buf, const char *Error, CmpType Cmp,
72 Optional<StringRef> ExternalFilePrependPath = None) {
73 std::string ErrorStr;
74 raw_string_ostream Stream(ErrorStr);
75
76 Expected<std::unique_ptr<remarks::RemarkParser>> MaybeParser =
77 remarks::createRemarkParserFromMeta(remarks::Format::YAML, Buf,
78 /*StrTab=*/None,
79 std::move(ExternalFilePrependPath));
80 handleAllErrors(MaybeParser.takeError(),
81 [&](const ErrorInfoBase &EIB) { EIB.log(Stream); });
82
83 // Use a case insensitive comparision due to case differences in error strings
84 // for different OSs.
85 if (Cmp == CmpType::Equal) {
86 EXPECT_EQ(StringRef(Stream.str()).lower(), StringRef(Error).lower());
87 }
88
89 if (Cmp == CmpType::Contains) {
90 EXPECT_TRUE(StringRef(Stream.str()).contains(StringRef(Error)));
91 }
92 }
93
TEST(YAMLRemarks,ParsingEmpty)94 TEST(YAMLRemarks, ParsingEmpty) {
95 EXPECT_TRUE(parseExpectError("\n\n", "document root is not of mapping type."));
96 }
97
TEST(YAMLRemarks,ParsingNotYAML)98 TEST(YAMLRemarks, ParsingNotYAML) {
99 EXPECT_TRUE(
100 parseExpectError("\x01\x02\x03\x04\x05\x06", "Got empty plain scalar"));
101 }
102
TEST(YAMLRemarks,ParsingGood)103 TEST(YAMLRemarks, ParsingGood) {
104 parseGood("\n"
105 "--- !Missed\n"
106 "Pass: inline\n"
107 "Name: NoDefinition\n"
108 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
109 "Function: foo\n"
110 "Args:\n"
111 " - Callee: bar\n"
112 " - String: ' will not be inlined into '\n"
113 " - Caller: foo\n"
114 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
115 " - String: ' because its definition is unavailable'\n"
116 "");
117
118 // No debug loc should also pass.
119 parseGood("\n"
120 "--- !Missed\n"
121 "Pass: inline\n"
122 "Name: NoDefinition\n"
123 "Function: foo\n"
124 "Args:\n"
125 " - Callee: bar\n"
126 " - String: ' will not be inlined into '\n"
127 " - Caller: foo\n"
128 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
129 " - String: ' because its definition is unavailable'\n"
130 "");
131
132 // No args is also ok.
133 parseGood("\n"
134 "--- !Missed\n"
135 "Pass: inline\n"
136 "Name: NoDefinition\n"
137 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
138 "Function: foo\n"
139 "");
140
141 // Different order.
142 parseGood("\n"
143 "--- !Missed\n"
144 "DebugLoc: { Line: 3, Column: 12, File: file.c }\n"
145 "Function: foo\n"
146 "Name: NoDefinition\n"
147 "Args:\n"
148 " - Callee: bar\n"
149 " - String: ' will not be inlined into '\n"
150 " - Caller: foo\n"
151 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
152 " - String: ' because its definition is unavailable'\n"
153 "Pass: inline\n"
154 "");
155 }
156
157 // Mandatory common part of a remark.
158 #define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n\n"
159 // Test all the types.
TEST(YAMLRemarks,ParsingTypes)160 TEST(YAMLRemarks, ParsingTypes) {
161 // Type: Passed
162 parseGood("--- !Passed" COMMON_REMARK);
163 // Type: Missed
164 parseGood("--- !Missed" COMMON_REMARK);
165 // Type: Analysis
166 parseGood("--- !Analysis" COMMON_REMARK);
167 // Type: AnalysisFPCommute
168 parseGood("--- !AnalysisFPCommute" COMMON_REMARK);
169 // Type: AnalysisAliasing
170 parseGood("--- !AnalysisAliasing" COMMON_REMARK);
171 // Type: Failure
172 parseGood("--- !Failure" COMMON_REMARK);
173 }
174 #undef COMMON_REMARK
175
TEST(YAMLRemarks,ParsingMissingFields)176 TEST(YAMLRemarks, ParsingMissingFields) {
177 // No type.
178 EXPECT_TRUE(parseExpectError("\n"
179 "---\n"
180 "Pass: inline\n"
181 "Name: NoDefinition\n"
182 "Function: foo\n"
183 "",
184 "expected a remark tag."));
185 // No pass.
186 EXPECT_TRUE(parseExpectError("\n"
187 "--- !Missed\n"
188 "Name: NoDefinition\n"
189 "Function: foo\n"
190 "",
191 "Type, Pass, Name or Function missing."));
192 // No name.
193 EXPECT_TRUE(parseExpectError("\n"
194 "--- !Missed\n"
195 "Pass: inline\n"
196 "Function: foo\n"
197 "",
198 "Type, Pass, Name or Function missing."));
199 // No function.
200 EXPECT_TRUE(parseExpectError("\n"
201 "--- !Missed\n"
202 "Pass: inline\n"
203 "Name: NoDefinition\n"
204 "",
205 "Type, Pass, Name or Function missing."));
206 // Debug loc but no file.
207 EXPECT_TRUE(parseExpectError("\n"
208 "--- !Missed\n"
209 "Pass: inline\n"
210 "Name: NoDefinition\n"
211 "Function: foo\n"
212 "DebugLoc: { Line: 3, Column: 12 }\n"
213 "",
214 "DebugLoc node incomplete."));
215 // Debug loc but no line.
216 EXPECT_TRUE(parseExpectError("\n"
217 "--- !Missed\n"
218 "Pass: inline\n"
219 "Name: NoDefinition\n"
220 "Function: foo\n"
221 "DebugLoc: { File: file.c, Column: 12 }\n"
222 "",
223 "DebugLoc node incomplete."));
224 // Debug loc but no column.
225 EXPECT_TRUE(parseExpectError("\n"
226 "--- !Missed\n"
227 "Pass: inline\n"
228 "Name: NoDefinition\n"
229 "Function: foo\n"
230 "DebugLoc: { File: file.c, Line: 3 }\n"
231 "",
232 "DebugLoc node incomplete."));
233 }
234
TEST(YAMLRemarks,ParsingWrongTypes)235 TEST(YAMLRemarks, ParsingWrongTypes) {
236 // Wrong debug loc type.
237 EXPECT_TRUE(parseExpectError("\n"
238 "--- !Missed\n"
239 "Pass: inline\n"
240 "Name: NoDefinition\n"
241 "Function: foo\n"
242 "DebugLoc: foo\n"
243 "",
244 "expected a value of mapping type."));
245 // Wrong line type.
246 EXPECT_TRUE(parseExpectError("\n"
247 "--- !Missed\n"
248 "Pass: inline\n"
249 "Name: NoDefinition\n"
250 "Function: foo\n"
251 "DebugLoc: { File: file.c, Line: b, Column: 12 }\n"
252 "",
253 "expected a value of integer type."));
254 // Wrong column type.
255 EXPECT_TRUE(parseExpectError("\n"
256 "--- !Missed\n"
257 "Pass: inline\n"
258 "Name: NoDefinition\n"
259 "Function: foo\n"
260 "DebugLoc: { File: file.c, Line: 3, Column: c }\n"
261 "",
262 "expected a value of integer type."));
263 // Wrong args type.
264 EXPECT_TRUE(parseExpectError("\n"
265 "--- !Missed\n"
266 "Pass: inline\n"
267 "Name: NoDefinition\n"
268 "Function: foo\n"
269 "Args: foo\n"
270 "",
271 "wrong value type for key."));
272 // Wrong key type.
273 EXPECT_TRUE(parseExpectError("\n"
274 "--- !Missed\n"
275 "{ A: a }: inline\n"
276 "Name: NoDefinition\n"
277 "Function: foo\n"
278 "",
279 "key is not a string."));
280 // Debug loc with unknown entry.
281 EXPECT_TRUE(parseExpectError("\n"
282 "--- !Missed\n"
283 "Pass: inline\n"
284 "Name: NoDefinition\n"
285 "Function: foo\n"
286 "DebugLoc: { File: file.c, Column: 12, Unknown: 12 }\n"
287 "",
288 "unknown entry in DebugLoc map."));
289 // Unknown entry.
290 EXPECT_TRUE(parseExpectError("\n"
291 "--- !Missed\n"
292 "Unknown: inline\n"
293 "",
294 "unknown key."));
295 // Not a scalar.
296 EXPECT_TRUE(parseExpectError("\n"
297 "--- !Missed\n"
298 "Pass: { File: a, Line: 1, Column: 2 }\n"
299 "Name: NoDefinition\n"
300 "Function: foo\n"
301 "",
302 "expected a value of scalar type."));
303 // Not a string file in debug loc.
304 EXPECT_TRUE(parseExpectError("\n"
305 "--- !Missed\n"
306 "Pass: inline\n"
307 "Name: NoDefinition\n"
308 "Function: foo\n"
309 "DebugLoc: { File: { a: b }, Column: 12, Line: 12 }\n"
310 "",
311 "expected a value of scalar type."));
312 // Not a integer column in debug loc.
313 EXPECT_TRUE(parseExpectError("\n"
314 "--- !Missed\n"
315 "Pass: inline\n"
316 "Name: NoDefinition\n"
317 "Function: foo\n"
318 "DebugLoc: { File: file.c, Column: { a: b }, Line: 12 }\n"
319 "",
320 "expected a value of scalar type."));
321 // Not a integer line in debug loc.
322 EXPECT_TRUE(parseExpectError("\n"
323 "--- !Missed\n"
324 "Pass: inline\n"
325 "Name: NoDefinition\n"
326 "Function: foo\n"
327 "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n"
328 "",
329 "expected a value of scalar type."));
330 // Not a mapping type value for args.
331 EXPECT_TRUE(parseExpectError("\n"
332 "--- !Missed\n"
333 "Pass: inline\n"
334 "Name: NoDefinition\n"
335 "Function: foo\n"
336 "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n"
337 "",
338 "expected a value of scalar type."));
339 }
340
TEST(YAMLRemarks,ParsingWrongArgs)341 TEST(YAMLRemarks, ParsingWrongArgs) {
342 // Multiple debug locs per arg.
343 EXPECT_TRUE(parseExpectError("\n"
344 "--- !Missed\n"
345 "Pass: inline\n"
346 "Name: NoDefinition\n"
347 "Function: foo\n"
348 "Args:\n"
349 " - Str: string\n"
350 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
351 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
352 "",
353 "only one DebugLoc entry is allowed per argument."));
354 // Multiple strings per arg.
355 EXPECT_TRUE(parseExpectError("\n"
356 "--- !Missed\n"
357 "Pass: inline\n"
358 "Name: NoDefinition\n"
359 "Function: foo\n"
360 "Args:\n"
361 " - Str: string\n"
362 " Str2: string\n"
363 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
364 "",
365 "only one string entry is allowed per argument."));
366 // No arg value.
367 EXPECT_TRUE(parseExpectError("\n"
368 "--- !Missed\n"
369 "Pass: inline\n"
370 "Name: NoDefinition\n"
371 "Function: foo\n"
372 "Args:\n"
373 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
374 "",
375 "argument key is missing."));
376 }
377
checkStr(StringRef Str,unsigned ExpectedLen)378 static inline StringRef checkStr(StringRef Str, unsigned ExpectedLen) {
379 const char *StrData = Str.data();
380 unsigned StrLen = Str.size();
381 EXPECT_EQ(StrLen, ExpectedLen);
382 return StringRef(StrData, StrLen);
383 }
384
TEST(YAMLRemarks,Contents)385 TEST(YAMLRemarks, Contents) {
386 StringRef Buf = "\n"
387 "--- !Missed\n"
388 "Pass: inline\n"
389 "Name: NoDefinition\n"
390 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
391 "Function: foo\n"
392 "Hotness: 4\n"
393 "Args:\n"
394 " - Callee: bar\n"
395 " - String: ' will not be inlined into '\n"
396 " - Caller: foo\n"
397 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
398 " - String: ' because its definition is unavailable'\n"
399 "\n";
400
401 Expected<std::unique_ptr<remarks::RemarkParser>> MaybeParser =
402 remarks::createRemarkParser(remarks::Format::YAML, Buf);
403 EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
404 EXPECT_TRUE(*MaybeParser != nullptr);
405
406 remarks::RemarkParser &Parser = **MaybeParser;
407 Expected<std::unique_ptr<remarks::Remark>> MaybeRemark = Parser.next();
408 EXPECT_FALSE(
409 errorToBool(MaybeRemark.takeError())); // Check for parsing errors.
410 EXPECT_TRUE(*MaybeRemark != nullptr); // At least one remark.
411
412 const remarks::Remark &Remark = **MaybeRemark;
413 EXPECT_EQ(Remark.RemarkType, remarks::Type::Missed);
414 EXPECT_EQ(checkStr(Remark.PassName, 6), "inline");
415 EXPECT_EQ(checkStr(Remark.RemarkName, 12), "NoDefinition");
416 EXPECT_EQ(checkStr(Remark.FunctionName, 3), "foo");
417 EXPECT_TRUE(Remark.Loc);
418 const remarks::RemarkLocation &RL = *Remark.Loc;
419 EXPECT_EQ(checkStr(RL.SourceFilePath, 6), "file.c");
420 EXPECT_EQ(RL.SourceLine, 3U);
421 EXPECT_EQ(RL.SourceColumn, 12U);
422 EXPECT_TRUE(Remark.Hotness);
423 EXPECT_EQ(*Remark.Hotness, 4U);
424 EXPECT_EQ(Remark.Args.size(), 4U);
425
426 unsigned ArgID = 0;
427 for (const remarks::Argument &Arg : Remark.Args) {
428 switch (ArgID) {
429 case 0:
430 EXPECT_EQ(checkStr(Arg.Key, 6), "Callee");
431 EXPECT_EQ(checkStr(Arg.Val, 3), "bar");
432 EXPECT_FALSE(Arg.Loc);
433 break;
434 case 1:
435 EXPECT_EQ(checkStr(Arg.Key, 6), "String");
436 EXPECT_EQ(checkStr(Arg.Val, 26), " will not be inlined into ");
437 EXPECT_FALSE(Arg.Loc);
438 break;
439 case 2: {
440 EXPECT_EQ(checkStr(Arg.Key, 6), "Caller");
441 EXPECT_EQ(checkStr(Arg.Val, 3), "foo");
442 EXPECT_TRUE(Arg.Loc);
443 const remarks::RemarkLocation &RL = *Arg.Loc;
444 EXPECT_EQ(checkStr(RL.SourceFilePath, 6), "file.c");
445 EXPECT_EQ(RL.SourceLine, 2U);
446 EXPECT_EQ(RL.SourceColumn, 0U);
447 break;
448 }
449 case 3:
450 EXPECT_EQ(checkStr(Arg.Key, 6), "String");
451 EXPECT_EQ(checkStr(Arg.Val, 38),
452 " because its definition is unavailable");
453 EXPECT_FALSE(Arg.Loc);
454 break;
455 default:
456 break;
457 }
458 ++ArgID;
459 }
460
461 MaybeRemark = Parser.next();
462 Error E = MaybeRemark.takeError();
463 EXPECT_TRUE(E.isA<remarks::EndOfFileError>());
464 EXPECT_TRUE(errorToBool(std::move(E))); // Check for parsing errors.
465 }
466
checkStr(LLVMRemarkStringRef Str,unsigned ExpectedLen)467 static inline StringRef checkStr(LLVMRemarkStringRef Str,
468 unsigned ExpectedLen) {
469 const char *StrData = LLVMRemarkStringGetData(Str);
470 unsigned StrLen = LLVMRemarkStringGetLen(Str);
471 EXPECT_EQ(StrLen, ExpectedLen);
472 return StringRef(StrData, StrLen);
473 }
474
TEST(YAMLRemarks,ContentsCAPI)475 TEST(YAMLRemarks, ContentsCAPI) {
476 StringRef Buf = "\n"
477 "--- !Missed\n"
478 "Pass: inline\n"
479 "Name: NoDefinition\n"
480 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
481 "Function: foo\n"
482 "Args:\n"
483 " - Callee: bar\n"
484 " - String: ' will not be inlined into '\n"
485 " - Caller: foo\n"
486 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
487 " - String: ' because its definition is unavailable'\n"
488 "\n";
489
490 LLVMRemarkParserRef Parser =
491 LLVMRemarkParserCreateYAML(Buf.data(), Buf.size());
492 LLVMRemarkEntryRef Remark = LLVMRemarkParserGetNext(Parser);
493 EXPECT_FALSE(Remark == nullptr);
494 EXPECT_EQ(LLVMRemarkEntryGetType(Remark), LLVMRemarkTypeMissed);
495 EXPECT_EQ(checkStr(LLVMRemarkEntryGetPassName(Remark), 6), "inline");
496 EXPECT_EQ(checkStr(LLVMRemarkEntryGetRemarkName(Remark), 12), "NoDefinition");
497 EXPECT_EQ(checkStr(LLVMRemarkEntryGetFunctionName(Remark), 3), "foo");
498 LLVMRemarkDebugLocRef DL = LLVMRemarkEntryGetDebugLoc(Remark);
499 EXPECT_EQ(checkStr(LLVMRemarkDebugLocGetSourceFilePath(DL), 6), "file.c");
500 EXPECT_EQ(LLVMRemarkDebugLocGetSourceLine(DL), 3U);
501 EXPECT_EQ(LLVMRemarkDebugLocGetSourceColumn(DL), 12U);
502 EXPECT_EQ(LLVMRemarkEntryGetHotness(Remark), 0U);
503 EXPECT_EQ(LLVMRemarkEntryGetNumArgs(Remark), 4U);
504
505 unsigned ArgID = 0;
506 LLVMRemarkArgRef Arg = LLVMRemarkEntryGetFirstArg(Remark);
507 do {
508 switch (ArgID) {
509 case 0:
510 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "Callee");
511 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 3), "bar");
512 EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr);
513 break;
514 case 1:
515 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "String");
516 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 26),
517 " will not be inlined into ");
518 EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr);
519 break;
520 case 2: {
521 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "Caller");
522 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 3), "foo");
523 LLVMRemarkDebugLocRef DL = LLVMRemarkArgGetDebugLoc(Arg);
524 EXPECT_EQ(checkStr(LLVMRemarkDebugLocGetSourceFilePath(DL), 6), "file.c");
525 EXPECT_EQ(LLVMRemarkDebugLocGetSourceLine(DL), 2U);
526 EXPECT_EQ(LLVMRemarkDebugLocGetSourceColumn(DL), 0U);
527 break;
528 }
529 case 3:
530 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "String");
531 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 38),
532 " because its definition is unavailable");
533 EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr);
534 break;
535 default:
536 break;
537 }
538 ++ArgID;
539 } while ((Arg = LLVMRemarkEntryGetNextArg(Arg, Remark)));
540
541 LLVMRemarkEntryDispose(Remark);
542
543 EXPECT_EQ(LLVMRemarkParserGetNext(Parser), nullptr);
544
545 EXPECT_FALSE(LLVMRemarkParserHasError(Parser));
546 LLVMRemarkParserDispose(Parser);
547 }
548
TEST(YAMLRemarks,ContentsStrTab)549 TEST(YAMLRemarks, ContentsStrTab) {
550 StringRef Buf = "\n"
551 "--- !Missed\n"
552 "Pass: 0\n"
553 "Name: 1\n"
554 "DebugLoc: { File: 2, Line: 3, Column: 12 }\n"
555 "Function: 3\n"
556 "Hotness: 4\n"
557 "Args:\n"
558 " - Callee: 5\n"
559 " - String: 7\n"
560 " - Caller: 3\n"
561 " DebugLoc: { File: 2, Line: 2, Column: 0 }\n"
562 " - String: 8\n"
563 "\n";
564
565 StringRef StrTabBuf =
566 StringRef("inline\0NoDefinition\0file.c\0foo\0Callee\0bar\0String\0 "
567 "will not be inlined into \0 because its definition is "
568 "unavailable",
569 115);
570
571 remarks::ParsedStringTable StrTab(StrTabBuf);
572 Expected<std::unique_ptr<remarks::RemarkParser>> MaybeParser =
573 remarks::createRemarkParser(remarks::Format::YAMLStrTab, Buf,
574 std::move(StrTab));
575 EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
576 EXPECT_TRUE(*MaybeParser != nullptr);
577
578 remarks::RemarkParser &Parser = **MaybeParser;
579 Expected<std::unique_ptr<remarks::Remark>> MaybeRemark = Parser.next();
580 EXPECT_FALSE(
581 errorToBool(MaybeRemark.takeError())); // Check for parsing errors.
582 EXPECT_TRUE(*MaybeRemark != nullptr); // At least one remark.
583
584 const remarks::Remark &Remark = **MaybeRemark;
585 EXPECT_EQ(Remark.RemarkType, remarks::Type::Missed);
586 EXPECT_EQ(checkStr(Remark.PassName, 6), "inline");
587 EXPECT_EQ(checkStr(Remark.RemarkName, 12), "NoDefinition");
588 EXPECT_EQ(checkStr(Remark.FunctionName, 3), "foo");
589 EXPECT_TRUE(Remark.Loc);
590 const remarks::RemarkLocation &RL = *Remark.Loc;
591 EXPECT_EQ(checkStr(RL.SourceFilePath, 6), "file.c");
592 EXPECT_EQ(RL.SourceLine, 3U);
593 EXPECT_EQ(RL.SourceColumn, 12U);
594 EXPECT_TRUE(Remark.Hotness);
595 EXPECT_EQ(*Remark.Hotness, 4U);
596 EXPECT_EQ(Remark.Args.size(), 4U);
597
598 unsigned ArgID = 0;
599 for (const remarks::Argument &Arg : Remark.Args) {
600 switch (ArgID) {
601 case 0:
602 EXPECT_EQ(checkStr(Arg.Key, 6), "Callee");
603 EXPECT_EQ(checkStr(Arg.Val, 3), "bar");
604 EXPECT_FALSE(Arg.Loc);
605 break;
606 case 1:
607 EXPECT_EQ(checkStr(Arg.Key, 6), "String");
608 EXPECT_EQ(checkStr(Arg.Val, 26), " will not be inlined into ");
609 EXPECT_FALSE(Arg.Loc);
610 break;
611 case 2: {
612 EXPECT_EQ(checkStr(Arg.Key, 6), "Caller");
613 EXPECT_EQ(checkStr(Arg.Val, 3), "foo");
614 EXPECT_TRUE(Arg.Loc);
615 const remarks::RemarkLocation &RL = *Arg.Loc;
616 EXPECT_EQ(checkStr(RL.SourceFilePath, 6), "file.c");
617 EXPECT_EQ(RL.SourceLine, 2U);
618 EXPECT_EQ(RL.SourceColumn, 0U);
619 break;
620 }
621 case 3:
622 EXPECT_EQ(checkStr(Arg.Key, 6), "String");
623 EXPECT_EQ(checkStr(Arg.Val, 38),
624 " because its definition is unavailable");
625 EXPECT_FALSE(Arg.Loc);
626 break;
627 default:
628 break;
629 }
630 ++ArgID;
631 }
632
633 MaybeRemark = Parser.next();
634 Error E = MaybeRemark.takeError();
635 EXPECT_TRUE(E.isA<remarks::EndOfFileError>());
636 EXPECT_TRUE(errorToBool(std::move(E))); // Check for parsing errors.
637 }
638
TEST(YAMLRemarks,ParsingBadStringTableIndex)639 TEST(YAMLRemarks, ParsingBadStringTableIndex) {
640 StringRef Buf = "\n"
641 "--- !Missed\n"
642 "Pass: 50\n"
643 "\n";
644
645 StringRef StrTabBuf = StringRef("inline");
646
647 remarks::ParsedStringTable StrTab(StrTabBuf);
648 Expected<std::unique_ptr<remarks::RemarkParser>> MaybeParser =
649 remarks::createRemarkParser(remarks::Format::YAMLStrTab, Buf,
650 std::move(StrTab));
651 EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
652 EXPECT_TRUE(*MaybeParser != nullptr);
653
654 remarks::RemarkParser &Parser = **MaybeParser;
655 Expected<std::unique_ptr<remarks::Remark>> MaybeRemark = Parser.next();
656 EXPECT_FALSE(MaybeRemark); // Expect an error here.
657
658 std::string ErrorStr;
659 raw_string_ostream Stream(ErrorStr);
660 handleAllErrors(MaybeRemark.takeError(),
661 [&](const ErrorInfoBase &EIB) { EIB.log(Stream); });
662 EXPECT_TRUE(
663 StringRef(Stream.str())
664 .contains("String with index 50 is out of bounds (size = 1)."));
665 }
666
TEST(YAMLRemarks,ParsingGoodMeta)667 TEST(YAMLRemarks, ParsingGoodMeta) {
668 // No metadata should also work.
669 parseGoodMeta("--- !Missed\n"
670 "Pass: inline\n"
671 "Name: NoDefinition\n"
672 "Function: foo\n");
673
674 // No string table.
675 parseGoodMeta(StringRef("REMARKS\0"
676 "\0\0\0\0\0\0\0\0"
677 "\0\0\0\0\0\0\0\0"
678 "--- !Missed\n"
679 "Pass: inline\n"
680 "Name: NoDefinition\n"
681 "Function: foo\n",
682 82));
683
684 // Use the string table from the metadata.
685 parseGoodMeta(StringRef("REMARKS\0"
686 "\0\0\0\0\0\0\0\0"
687 "\x02\0\0\0\0\0\0\0"
688 "a\0"
689 "--- !Missed\n"
690 "Pass: 0\n"
691 "Name: 0\n"
692 "Function: 0\n",
693 66));
694 }
695
TEST(YAMLRemarks,ParsingBadMeta)696 TEST(YAMLRemarks, ParsingBadMeta) {
697 parseExpectErrorMeta(StringRef("REMARKSS", 9),
698 "Expecting \\0 after magic number.", CmpType::Equal);
699
700 parseExpectErrorMeta(StringRef("REMARKS\0", 8), "Expecting version number.",
701 CmpType::Equal);
702
703 parseExpectErrorMeta(StringRef("REMARKS\0"
704 "\x09\0\0\0\0\0\0\0",
705 16),
706 "Mismatching remark version. Got 9, expected 0.",
707 CmpType::Equal);
708
709 parseExpectErrorMeta(StringRef("REMARKS\0"
710 "\0\0\0\0\0\0\0\0",
711 16),
712 "Expecting string table size.", CmpType::Equal);
713
714 parseExpectErrorMeta(StringRef("REMARKS\0"
715 "\0\0\0\0\0\0\0\0"
716 "\x01\0\0\0\0\0\0\0",
717 24),
718 "Expecting string table.", CmpType::Equal);
719
720 parseExpectErrorMeta(StringRef("REMARKS\0"
721 "\0\0\0\0\0\0\0\0"
722 "\0\0\0\0\0\0\0\0"
723 "/path/",
724 30),
725 "'/path/'", CmpType::Contains);
726
727 parseExpectErrorMeta(StringRef("REMARKS\0"
728 "\0\0\0\0\0\0\0\0"
729 "\0\0\0\0\0\0\0\0"
730 "/path/",
731 30),
732 "'/baddir/path/'", CmpType::Contains,
733 StringRef("/baddir/"));
734 }
735