1 //===- unittest/Support/YAMLRemarksParsingTest.cpp - OptTable tests -------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm-c/Remarks.h"
10 #include "llvm/Remarks/Remark.h"
11 #include "llvm/Remarks/RemarkParser.h"
12 #include "gtest/gtest.h"
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);
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.
33 bool parseExpectError(const char (&Buf
)[N
], const char *Error
) {
34 Expected
<std::unique_ptr
<remarks::RemarkParser
>> MaybeParser
=
35 remarks::createRemarkParser(remarks::Format::YAML
, {Buf
, N
- 1});
36 EXPECT_FALSE(errorToBool(MaybeParser
.takeError()));
37 EXPECT_TRUE(*MaybeParser
!= nullptr);
39 remarks::RemarkParser
&Parser
= **MaybeParser
;
40 Expected
<std::unique_ptr
<remarks::Remark
>> Remark
= Parser
.next();
41 EXPECT_FALSE(Remark
); // Check for parsing errors.
44 raw_string_ostream
Stream(ErrorStr
);
45 handleAllErrors(Remark
.takeError(),
46 [&](const ErrorInfoBase
&EIB
) { EIB
.log(Stream
); });
47 return StringRef(Stream
.str()).contains(Error
);
50 TEST(YAMLRemarks
, ParsingEmpty
) {
51 EXPECT_TRUE(parseExpectError("\n\n", "document root is not of mapping type."));
54 TEST(YAMLRemarks
, ParsingNotYAML
) {
56 parseExpectError("\x01\x02\x03\x04\x05\x06", "Got empty plain scalar"));
59 TEST(YAMLRemarks
, ParsingGood
) {
63 "Name: NoDefinition\n"
64 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
68 " - String: ' will not be inlined into '\n"
70 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
71 " - String: ' because its definition is unavailable'\n"
74 // No debug loc should also pass.
78 "Name: NoDefinition\n"
82 " - String: ' will not be inlined into '\n"
84 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
85 " - String: ' because its definition is unavailable'\n"
88 // No args is also ok.
92 "Name: NoDefinition\n"
93 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
100 "DebugLoc: { Line: 3, Column: 12, File: file.c }\n"
102 "Name: NoDefinition\n"
105 " - String: ' will not be inlined into '\n"
107 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
108 " - String: ' because its definition is unavailable'\n"
113 // Mandatory common part of a remark.
114 #define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n\n"
115 // Test all the types.
116 TEST(YAMLRemarks
, ParsingTypes
) {
118 parseGood("--- !Passed" COMMON_REMARK
);
120 parseGood("--- !Missed" COMMON_REMARK
);
122 parseGood("--- !Analysis" COMMON_REMARK
);
123 // Type: AnalysisFPCommute
124 parseGood("--- !AnalysisFPCommute" COMMON_REMARK
);
125 // Type: AnalysisAliasing
126 parseGood("--- !AnalysisAliasing" COMMON_REMARK
);
128 parseGood("--- !Failure" COMMON_REMARK
);
132 TEST(YAMLRemarks
, ParsingMissingFields
) {
134 EXPECT_TRUE(parseExpectError("\n"
137 "Name: NoDefinition\n"
140 "expected a remark tag."));
142 EXPECT_TRUE(parseExpectError("\n"
144 "Name: NoDefinition\n"
147 "Type, Pass, Name or Function missing."));
149 EXPECT_TRUE(parseExpectError("\n"
154 "Type, Pass, Name or Function missing."));
156 EXPECT_TRUE(parseExpectError("\n"
159 "Name: NoDefinition\n"
161 "Type, Pass, Name or Function missing."));
162 // Debug loc but no file.
163 EXPECT_TRUE(parseExpectError("\n"
166 "Name: NoDefinition\n"
168 "DebugLoc: { Line: 3, Column: 12 }\n"
170 "DebugLoc node incomplete."));
171 // Debug loc but no line.
172 EXPECT_TRUE(parseExpectError("\n"
175 "Name: NoDefinition\n"
177 "DebugLoc: { File: file.c, Column: 12 }\n"
179 "DebugLoc node incomplete."));
180 // Debug loc but no column.
181 EXPECT_TRUE(parseExpectError("\n"
184 "Name: NoDefinition\n"
186 "DebugLoc: { File: file.c, Line: 3 }\n"
188 "DebugLoc node incomplete."));
191 TEST(YAMLRemarks
, ParsingWrongTypes
) {
192 // Wrong debug loc type.
193 EXPECT_TRUE(parseExpectError("\n"
196 "Name: NoDefinition\n"
200 "expected a value of mapping type."));
202 EXPECT_TRUE(parseExpectError("\n"
205 "Name: NoDefinition\n"
207 "DebugLoc: { File: file.c, Line: b, Column: 12 }\n"
209 "expected a value of integer type."));
210 // Wrong column type.
211 EXPECT_TRUE(parseExpectError("\n"
214 "Name: NoDefinition\n"
216 "DebugLoc: { File: file.c, Line: 3, Column: c }\n"
218 "expected a value of integer type."));
220 EXPECT_TRUE(parseExpectError("\n"
223 "Name: NoDefinition\n"
227 "wrong value type for key."));
229 EXPECT_TRUE(parseExpectError("\n"
232 "Name: NoDefinition\n"
235 "key is not a string."));
236 // Debug loc with unknown entry.
237 EXPECT_TRUE(parseExpectError("\n"
240 "Name: NoDefinition\n"
242 "DebugLoc: { File: file.c, Column: 12, Unknown: 12 }\n"
244 "unknown entry in DebugLoc map."));
246 EXPECT_TRUE(parseExpectError("\n"
252 EXPECT_TRUE(parseExpectError("\n"
254 "Pass: { File: a, Line: 1, Column: 2 }\n"
255 "Name: NoDefinition\n"
258 "expected a value of scalar type."));
259 // Not a string file in debug loc.
260 EXPECT_TRUE(parseExpectError("\n"
263 "Name: NoDefinition\n"
265 "DebugLoc: { File: { a: b }, Column: 12, Line: 12 }\n"
267 "expected a value of scalar type."));
268 // Not a integer column in debug loc.
269 EXPECT_TRUE(parseExpectError("\n"
272 "Name: NoDefinition\n"
274 "DebugLoc: { File: file.c, Column: { a: b }, Line: 12 }\n"
276 "expected a value of scalar type."));
277 // Not a integer line in debug loc.
278 EXPECT_TRUE(parseExpectError("\n"
281 "Name: NoDefinition\n"
283 "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n"
285 "expected a value of scalar type."));
286 // Not a mapping type value for args.
287 EXPECT_TRUE(parseExpectError("\n"
290 "Name: NoDefinition\n"
292 "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n"
294 "expected a value of scalar type."));
297 TEST(YAMLRemarks
, ParsingWrongArgs
) {
298 // Multiple debug locs per arg.
299 EXPECT_TRUE(parseExpectError("\n"
302 "Name: NoDefinition\n"
306 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
307 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
309 "only one DebugLoc entry is allowed per argument."));
310 // Multiple strings per arg.
311 EXPECT_TRUE(parseExpectError("\n"
314 "Name: NoDefinition\n"
319 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
321 "only one string entry is allowed per argument."));
323 EXPECT_TRUE(parseExpectError("\n"
326 "Name: NoDefinition\n"
329 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
331 "argument key is missing."));
334 static inline StringRef
checkStr(StringRef Str
, unsigned ExpectedLen
) {
335 const char *StrData
= Str
.data();
336 unsigned StrLen
= Str
.size();
337 EXPECT_EQ(StrLen
, ExpectedLen
);
338 return StringRef(StrData
, StrLen
);
341 TEST(YAMLRemarks
, Contents
) {
345 "Name: NoDefinition\n"
346 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
351 " - String: ' will not be inlined into '\n"
353 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
354 " - String: ' because its definition is unavailable'\n"
357 Expected
<std::unique_ptr
<remarks::RemarkParser
>> MaybeParser
=
358 remarks::createRemarkParser(remarks::Format::YAML
, Buf
);
359 EXPECT_FALSE(errorToBool(MaybeParser
.takeError()));
360 EXPECT_TRUE(*MaybeParser
!= nullptr);
362 remarks::RemarkParser
&Parser
= **MaybeParser
;
363 Expected
<std::unique_ptr
<remarks::Remark
>> MaybeRemark
= Parser
.next();
365 errorToBool(MaybeRemark
.takeError())); // Check for parsing errors.
366 EXPECT_TRUE(*MaybeRemark
!= nullptr); // At least one remark.
368 const remarks::Remark
&Remark
= **MaybeRemark
;
369 EXPECT_EQ(Remark
.RemarkType
, remarks::Type::Missed
);
370 EXPECT_EQ(checkStr(Remark
.PassName
, 6), "inline");
371 EXPECT_EQ(checkStr(Remark
.RemarkName
, 12), "NoDefinition");
372 EXPECT_EQ(checkStr(Remark
.FunctionName
, 3), "foo");
373 EXPECT_TRUE(Remark
.Loc
);
374 const remarks::RemarkLocation
&RL
= *Remark
.Loc
;
375 EXPECT_EQ(checkStr(RL
.SourceFilePath
, 6), "file.c");
376 EXPECT_EQ(RL
.SourceLine
, 3U);
377 EXPECT_EQ(RL
.SourceColumn
, 12U);
378 EXPECT_TRUE(Remark
.Hotness
);
379 EXPECT_EQ(*Remark
.Hotness
, 4U);
380 EXPECT_EQ(Remark
.Args
.size(), 4U);
383 for (const remarks::Argument
&Arg
: Remark
.Args
) {
386 EXPECT_EQ(checkStr(Arg
.Key
, 6), "Callee");
387 EXPECT_EQ(checkStr(Arg
.Val
, 3), "bar");
388 EXPECT_FALSE(Arg
.Loc
);
391 EXPECT_EQ(checkStr(Arg
.Key
, 6), "String");
392 EXPECT_EQ(checkStr(Arg
.Val
, 26), " will not be inlined into ");
393 EXPECT_FALSE(Arg
.Loc
);
396 EXPECT_EQ(checkStr(Arg
.Key
, 6), "Caller");
397 EXPECT_EQ(checkStr(Arg
.Val
, 3), "foo");
398 EXPECT_TRUE(Arg
.Loc
);
399 const remarks::RemarkLocation
&RL
= *Arg
.Loc
;
400 EXPECT_EQ(checkStr(RL
.SourceFilePath
, 6), "file.c");
401 EXPECT_EQ(RL
.SourceLine
, 2U);
402 EXPECT_EQ(RL
.SourceColumn
, 0U);
406 EXPECT_EQ(checkStr(Arg
.Key
, 6), "String");
407 EXPECT_EQ(checkStr(Arg
.Val
, 38),
408 " because its definition is unavailable");
409 EXPECT_FALSE(Arg
.Loc
);
417 MaybeRemark
= Parser
.next();
418 Error E
= MaybeRemark
.takeError();
419 EXPECT_TRUE(E
.isA
<remarks::EndOfFileError
>());
420 EXPECT_TRUE(errorToBool(std::move(E
))); // Check for parsing errors.
423 static inline StringRef
checkStr(LLVMRemarkStringRef Str
,
424 unsigned ExpectedLen
) {
425 const char *StrData
= LLVMRemarkStringGetData(Str
);
426 unsigned StrLen
= LLVMRemarkStringGetLen(Str
);
427 EXPECT_EQ(StrLen
, ExpectedLen
);
428 return StringRef(StrData
, StrLen
);
431 TEST(YAMLRemarks
, ContentsCAPI
) {
435 "Name: NoDefinition\n"
436 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
440 " - String: ' will not be inlined into '\n"
442 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
443 " - String: ' because its definition is unavailable'\n"
446 LLVMRemarkParserRef Parser
=
447 LLVMRemarkParserCreateYAML(Buf
.data(), Buf
.size());
448 LLVMRemarkEntryRef Remark
= LLVMRemarkParserGetNext(Parser
);
449 EXPECT_FALSE(Remark
== nullptr);
450 EXPECT_EQ(LLVMRemarkEntryGetType(Remark
), LLVMRemarkTypeMissed
);
451 EXPECT_EQ(checkStr(LLVMRemarkEntryGetPassName(Remark
), 6), "inline");
452 EXPECT_EQ(checkStr(LLVMRemarkEntryGetRemarkName(Remark
), 12), "NoDefinition");
453 EXPECT_EQ(checkStr(LLVMRemarkEntryGetFunctionName(Remark
), 3), "foo");
454 LLVMRemarkDebugLocRef DL
= LLVMRemarkEntryGetDebugLoc(Remark
);
455 EXPECT_EQ(checkStr(LLVMRemarkDebugLocGetSourceFilePath(DL
), 6), "file.c");
456 EXPECT_EQ(LLVMRemarkDebugLocGetSourceLine(DL
), 3U);
457 EXPECT_EQ(LLVMRemarkDebugLocGetSourceColumn(DL
), 12U);
458 EXPECT_EQ(LLVMRemarkEntryGetHotness(Remark
), 0U);
459 EXPECT_EQ(LLVMRemarkEntryGetNumArgs(Remark
), 4U);
462 LLVMRemarkArgRef Arg
= LLVMRemarkEntryGetFirstArg(Remark
);
466 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg
), 6), "Callee");
467 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg
), 3), "bar");
468 EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg
), nullptr);
471 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg
), 6), "String");
472 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg
), 26),
473 " will not be inlined into ");
474 EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg
), nullptr);
477 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg
), 6), "Caller");
478 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg
), 3), "foo");
479 LLVMRemarkDebugLocRef DL
= LLVMRemarkArgGetDebugLoc(Arg
);
480 EXPECT_EQ(checkStr(LLVMRemarkDebugLocGetSourceFilePath(DL
), 6), "file.c");
481 EXPECT_EQ(LLVMRemarkDebugLocGetSourceLine(DL
), 2U);
482 EXPECT_EQ(LLVMRemarkDebugLocGetSourceColumn(DL
), 0U);
486 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg
), 6), "String");
487 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg
), 38),
488 " because its definition is unavailable");
489 EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg
), nullptr);
495 } while ((Arg
= LLVMRemarkEntryGetNextArg(Arg
, Remark
)));
497 LLVMRemarkEntryDispose(Remark
);
499 EXPECT_EQ(LLVMRemarkParserGetNext(Parser
), nullptr);
501 EXPECT_FALSE(LLVMRemarkParserHasError(Parser
));
502 LLVMRemarkParserDispose(Parser
);
505 TEST(YAMLRemarks
, ContentsStrTab
) {
510 "DebugLoc: { File: 2, Line: 3, Column: 12 }\n"
517 " DebugLoc: { File: 2, Line: 2, Column: 0 }\n"
521 StringRef StrTabBuf
=
522 StringRef("inline\0NoDefinition\0file.c\0foo\0Callee\0bar\0String\0 "
523 "will not be inlined into \0 because its definition is "
527 remarks::ParsedStringTable
StrTab(StrTabBuf
);
528 Expected
<std::unique_ptr
<remarks::RemarkParser
>> MaybeParser
=
529 remarks::createRemarkParser(remarks::Format::YAMLStrTab
, Buf
,
531 EXPECT_FALSE(errorToBool(MaybeParser
.takeError()));
532 EXPECT_TRUE(*MaybeParser
!= nullptr);
534 remarks::RemarkParser
&Parser
= **MaybeParser
;
535 Expected
<std::unique_ptr
<remarks::Remark
>> MaybeRemark
= Parser
.next();
537 errorToBool(MaybeRemark
.takeError())); // Check for parsing errors.
538 EXPECT_TRUE(*MaybeRemark
!= nullptr); // At least one remark.
540 const remarks::Remark
&Remark
= **MaybeRemark
;
541 EXPECT_EQ(Remark
.RemarkType
, remarks::Type::Missed
);
542 EXPECT_EQ(checkStr(Remark
.PassName
, 6), "inline");
543 EXPECT_EQ(checkStr(Remark
.RemarkName
, 12), "NoDefinition");
544 EXPECT_EQ(checkStr(Remark
.FunctionName
, 3), "foo");
545 EXPECT_TRUE(Remark
.Loc
);
546 const remarks::RemarkLocation
&RL
= *Remark
.Loc
;
547 EXPECT_EQ(checkStr(RL
.SourceFilePath
, 6), "file.c");
548 EXPECT_EQ(RL
.SourceLine
, 3U);
549 EXPECT_EQ(RL
.SourceColumn
, 12U);
550 EXPECT_TRUE(Remark
.Hotness
);
551 EXPECT_EQ(*Remark
.Hotness
, 4U);
552 EXPECT_EQ(Remark
.Args
.size(), 4U);
555 for (const remarks::Argument
&Arg
: Remark
.Args
) {
558 EXPECT_EQ(checkStr(Arg
.Key
, 6), "Callee");
559 EXPECT_EQ(checkStr(Arg
.Val
, 3), "bar");
560 EXPECT_FALSE(Arg
.Loc
);
563 EXPECT_EQ(checkStr(Arg
.Key
, 6), "String");
564 EXPECT_EQ(checkStr(Arg
.Val
, 26), " will not be inlined into ");
565 EXPECT_FALSE(Arg
.Loc
);
568 EXPECT_EQ(checkStr(Arg
.Key
, 6), "Caller");
569 EXPECT_EQ(checkStr(Arg
.Val
, 3), "foo");
570 EXPECT_TRUE(Arg
.Loc
);
571 const remarks::RemarkLocation
&RL
= *Arg
.Loc
;
572 EXPECT_EQ(checkStr(RL
.SourceFilePath
, 6), "file.c");
573 EXPECT_EQ(RL
.SourceLine
, 2U);
574 EXPECT_EQ(RL
.SourceColumn
, 0U);
578 EXPECT_EQ(checkStr(Arg
.Key
, 6), "String");
579 EXPECT_EQ(checkStr(Arg
.Val
, 38),
580 " because its definition is unavailable");
581 EXPECT_FALSE(Arg
.Loc
);
589 MaybeRemark
= Parser
.next();
590 Error E
= MaybeRemark
.takeError();
591 EXPECT_TRUE(E
.isA
<remarks::EndOfFileError
>());
592 EXPECT_TRUE(errorToBool(std::move(E
))); // Check for parsing errors.
595 TEST(YAMLRemarks
, ParsingBadStringTableIndex
) {
601 StringRef StrTabBuf
= StringRef("inline");
603 remarks::ParsedStringTable
StrTab(StrTabBuf
);
604 Expected
<std::unique_ptr
<remarks::RemarkParser
>> MaybeParser
=
605 remarks::createRemarkParser(remarks::Format::YAMLStrTab
, Buf
,
607 EXPECT_FALSE(errorToBool(MaybeParser
.takeError()));
608 EXPECT_TRUE(*MaybeParser
!= nullptr);
610 remarks::RemarkParser
&Parser
= **MaybeParser
;
611 Expected
<std::unique_ptr
<remarks::Remark
>> MaybeRemark
= Parser
.next();
612 EXPECT_FALSE(MaybeRemark
); // Expect an error here.
614 std::string ErrorStr
;
615 raw_string_ostream
Stream(ErrorStr
);
616 handleAllErrors(MaybeRemark
.takeError(),
617 [&](const ErrorInfoBase
&EIB
) { EIB
.log(Stream
); });
619 StringRef(Stream
.str())
620 .contains("String with index 50 is out of bounds (size = 1)."));