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