blob: 36dbb0c9518c612d89c9396c095abfedc3394f49 [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]) {
17 remarks::Parser Parser({Buf, N - 1});
18 Expected<const remarks::Remark *> Remark = Parser.getNext();
19 EXPECT_FALSE(errorToBool(Remark.takeError())); // Check for parsing errors.
20 EXPECT_TRUE(*Remark != nullptr); // At least one remark.
21 Remark = Parser.getNext();
22 EXPECT_FALSE(errorToBool(Remark.takeError())); // Check for parsing errors.
23 EXPECT_TRUE(*Remark == nullptr); // Check that there are no more remarks.
24}
25
26template <size_t N>
27bool parseExpectError(const char (&Buf)[N], const char *Error) {
28 remarks::Parser Parser({Buf, N - 1});
29 Expected<const remarks::Remark *> Remark = Parser.getNext();
30 EXPECT_FALSE(Remark); // Expect an error here.
31
32 std::string ErrorStr;
33 raw_string_ostream Stream(ErrorStr);
34 handleAllErrors(Remark.takeError(),
35 [&](const ErrorInfoBase &EIB) { EIB.log(Stream); });
36 return StringRef(Stream.str()).contains(Error);
37}
38
39TEST(YAMLRemarks, ParsingEmpty) {
40 EXPECT_TRUE(parseExpectError("\n\n", "document root is not of mapping type."));
41}
42
43TEST(YAMLRemarks, ParsingNotYAML) {
44 EXPECT_TRUE(
45 parseExpectError("\x01\x02\x03\x04\x05\x06", "not a valid YAML file."));
46}
47
48TEST(YAMLRemarks, ParsingGood) {
49 parseGood("\n"
50 "--- !Missed\n"
51 "Pass: inline\n"
52 "Name: NoDefinition\n"
53 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
54 "Function: foo\n"
55 "Args:\n"
56 " - Callee: bar\n"
57 " - String: ' will not be inlined into '\n"
58 " - Caller: foo\n"
59 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
60 " - String: ' because its definition is unavailable'\n"
61 "");
62
63 // No debug loc should also pass.
64 parseGood("\n"
65 "--- !Missed\n"
66 "Pass: inline\n"
67 "Name: NoDefinition\n"
68 "Function: foo\n"
69 "Args:\n"
70 " - Callee: bar\n"
71 " - String: ' will not be inlined into '\n"
72 " - Caller: foo\n"
73 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
74 " - String: ' because its definition is unavailable'\n"
75 "");
76
77 // No args is also ok.
78 parseGood("\n"
79 "--- !Missed\n"
80 "Pass: inline\n"
81 "Name: NoDefinition\n"
82 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
83 "Function: foo\n"
84 "");
85
86 // Different order.
87 parseGood("\n"
88 "--- !Missed\n"
89 "DebugLoc: { Line: 3, Column: 12, File: file.c }\n"
90 "Function: foo\n"
91 "Name: NoDefinition\n"
92 "Args:\n"
93 " - Callee: bar\n"
94 " - String: ' will not be inlined into '\n"
95 " - Caller: foo\n"
96 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
97 " - String: ' because its definition is unavailable'\n"
98 "Pass: inline\n"
99 "");
100}
101
102// Mandatory common part of a remark.
103#define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n\n"
104// Test all the types.
105TEST(YAMLRemarks, ParsingTypes) {
106 // Type: Passed
107 parseGood("--- !Passed" COMMON_REMARK);
108 // Type: Missed
109 parseGood("--- !Missed" COMMON_REMARK);
110 // Type: Analysis
111 parseGood("--- !Analysis" COMMON_REMARK);
112 // Type: AnalysisFPCommute
113 parseGood("--- !AnalysisFPCommute" COMMON_REMARK);
114 // Type: AnalysisAliasing
115 parseGood("--- !AnalysisAliasing" COMMON_REMARK);
116 // Type: Failure
117 parseGood("--- !Failure" COMMON_REMARK);
118}
119#undef COMMON_REMARK
120
121TEST(YAMLRemarks, ParsingMissingFields) {
122 // No type.
123 EXPECT_TRUE(parseExpectError("\n"
124 "---\n"
125 "Pass: inline\n"
126 "Name: NoDefinition\n"
127 "Function: foo\n"
128 "",
129 "expected a remark tag."));
130 // No pass.
131 EXPECT_TRUE(parseExpectError("\n"
132 "--- !Missed\n"
133 "Name: NoDefinition\n"
134 "Function: foo\n"
135 "",
136 "Type, Pass, Name or Function missing."));
137 // No name.
138 EXPECT_TRUE(parseExpectError("\n"
139 "--- !Missed\n"
140 "Pass: inline\n"
141 "Function: foo\n"
142 "",
143 "Type, Pass, Name or Function missing."));
144 // No function.
145 EXPECT_TRUE(parseExpectError("\n"
146 "--- !Missed\n"
147 "Pass: inline\n"
148 "Name: NoDefinition\n"
149 "",
150 "Type, Pass, Name or Function missing."));
151 // Debug loc but no file.
152 EXPECT_TRUE(parseExpectError("\n"
153 "--- !Missed\n"
154 "Pass: inline\n"
155 "Name: NoDefinition\n"
156 "Function: foo\n"
157 "DebugLoc: { Line: 3, Column: 12 }\n"
158 "",
159 "DebugLoc node incomplete."));
160 // Debug loc but no line.
161 EXPECT_TRUE(parseExpectError("\n"
162 "--- !Missed\n"
163 "Pass: inline\n"
164 "Name: NoDefinition\n"
165 "Function: foo\n"
166 "DebugLoc: { File: file.c, Column: 12 }\n"
167 "",
168 "DebugLoc node incomplete."));
169 // Debug loc but no column.
170 EXPECT_TRUE(parseExpectError("\n"
171 "--- !Missed\n"
172 "Pass: inline\n"
173 "Name: NoDefinition\n"
174 "Function: foo\n"
175 "DebugLoc: { File: file.c, Line: 3 }\n"
176 "",
177 "DebugLoc node incomplete."));
178}
179
180TEST(YAMLRemarks, ParsingWrongTypes) {
181 // Wrong debug loc type.
182 EXPECT_TRUE(parseExpectError("\n"
183 "--- !Missed\n"
184 "Pass: inline\n"
185 "Name: NoDefinition\n"
186 "Function: foo\n"
187 "DebugLoc: foo\n"
188 "",
189 "expected a value of mapping type."));
190 // Wrong line type.
191 EXPECT_TRUE(parseExpectError("\n"
192 "--- !Missed\n"
193 "Pass: inline\n"
194 "Name: NoDefinition\n"
195 "Function: foo\n"
196 "DebugLoc: { File: file.c, Line: b, Column: 12 }\n"
197 "",
198 "expected a value of integer type."));
199 // Wrong column type.
200 EXPECT_TRUE(parseExpectError("\n"
201 "--- !Missed\n"
202 "Pass: inline\n"
203 "Name: NoDefinition\n"
204 "Function: foo\n"
205 "DebugLoc: { File: file.c, Line: 3, Column: c }\n"
206 "",
207 "expected a value of integer type."));
208 // Wrong args type.
209 EXPECT_TRUE(parseExpectError("\n"
210 "--- !Missed\n"
211 "Pass: inline\n"
212 "Name: NoDefinition\n"
213 "Function: foo\n"
214 "Args: foo\n"
215 "",
216 "wrong value type for key."));
217 // Wrong key type.
218 EXPECT_TRUE(parseExpectError("\n"
219 "--- !Missed\n"
220 "{ A: a }: inline\n"
221 "Name: NoDefinition\n"
222 "Function: foo\n"
223 "",
224 "key is not a string."));
225 // Debug loc with unknown entry.
226 EXPECT_TRUE(parseExpectError("\n"
227 "--- !Missed\n"
228 "Pass: inline\n"
229 "Name: NoDefinition\n"
230 "Function: foo\n"
231 "DebugLoc: { File: file.c, Column: 12, Unknown: 12 }\n"
232 "",
233 "unknown entry in DebugLoc map."));
234 // Unknown entry.
235 EXPECT_TRUE(parseExpectError("\n"
236 "--- !Missed\n"
237 "Unknown: inline\n"
238 "",
239 "unknown key."));
240 // Not a scalar.
241 EXPECT_TRUE(parseExpectError("\n"
242 "--- !Missed\n"
243 "Pass: { File: a, Line: 1, Column: 2 }\n"
244 "Name: NoDefinition\n"
245 "Function: foo\n"
246 "",
247 "expected a value of scalar type."));
248 // Not a string file in debug loc.
249 EXPECT_TRUE(parseExpectError("\n"
250 "--- !Missed\n"
251 "Pass: inline\n"
252 "Name: NoDefinition\n"
253 "Function: foo\n"
254 "DebugLoc: { File: { a: b }, Column: 12, Line: 12 }\n"
255 "",
256 "expected a value of scalar type."));
257 // Not a integer column in debug loc.
258 EXPECT_TRUE(parseExpectError("\n"
259 "--- !Missed\n"
260 "Pass: inline\n"
261 "Name: NoDefinition\n"
262 "Function: foo\n"
263 "DebugLoc: { File: file.c, Column: { a: b }, Line: 12 }\n"
264 "",
265 "expected a value of scalar type."));
266 // Not a integer line in debug loc.
267 EXPECT_TRUE(parseExpectError("\n"
268 "--- !Missed\n"
269 "Pass: inline\n"
270 "Name: NoDefinition\n"
271 "Function: foo\n"
272 "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n"
273 "",
274 "expected a value of scalar type."));
275 // Not a mapping type value for args.
276 EXPECT_TRUE(parseExpectError("\n"
277 "--- !Missed\n"
278 "Pass: inline\n"
279 "Name: NoDefinition\n"
280 "Function: foo\n"
281 "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n"
282 "",
283 "expected a value of scalar type."));
284}
285
286TEST(YAMLRemarks, ParsingWrongArgs) {
287 // Multiple debug locs per arg.
288 EXPECT_TRUE(parseExpectError("\n"
289 "--- !Missed\n"
290 "Pass: inline\n"
291 "Name: NoDefinition\n"
292 "Function: foo\n"
293 "Args:\n"
294 " - Str: string\n"
295 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
296 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
297 "",
298 "only one DebugLoc entry is allowed per argument."));
299 // Multiple strings per arg.
300 EXPECT_TRUE(parseExpectError("\n"
301 "--- !Missed\n"
302 "Pass: inline\n"
303 "Name: NoDefinition\n"
304 "Function: foo\n"
305 "Args:\n"
306 " - Str: string\n"
307 " Str2: string\n"
308 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
309 "",
310 "only one string entry is allowed per argument."));
311 // No arg value.
312 EXPECT_TRUE(parseExpectError("\n"
313 "--- !Missed\n"
314 "Pass: inline\n"
315 "Name: NoDefinition\n"
316 "Function: foo\n"
317 "Args:\n"
318 " - Callee: ''\n"
319 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
320 "",
321 "argument value is missing."));
322 // No arg value.
323 EXPECT_TRUE(parseExpectError("\n"
324 "--- !Missed\n"
325 "Pass: inline\n"
326 "Name: NoDefinition\n"
327 "Function: foo\n"
328 "Args:\n"
329 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
330 "",
331 "argument key is missing."));
332}
333
334static 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);
339}
340
341TEST(YAMLRemarks, Contents) {
342 StringRef Buf = "\n"
343 "--- !Missed\n"
344 "Pass: inline\n"
345 "Name: NoDefinition\n"
346 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
347 "Function: foo\n"
348 "Hotness: 4\n"
349 "Args:\n"
350 " - Callee: bar\n"
351 " - String: ' will not be inlined into '\n"
352 " - Caller: foo\n"
353 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
354 " - String: ' because its definition is unavailable'\n"
355 "\n";
356
357 remarks::Parser Parser(Buf);
358 Expected<const remarks::Remark *> RemarkOrErr = Parser.getNext();
359 EXPECT_FALSE(errorToBool(RemarkOrErr.takeError()));
360 EXPECT_TRUE(*RemarkOrErr != nullptr);
361
362 const remarks::Remark &Remark = **RemarkOrErr;
363 EXPECT_EQ(Remark.RemarkType, remarks::Type::Missed);
364 EXPECT_EQ(checkStr(Remark.PassName, 6), "inline");
365 EXPECT_EQ(checkStr(Remark.RemarkName, 12), "NoDefinition");
366 EXPECT_EQ(checkStr(Remark.FunctionName, 3), "foo");
367 EXPECT_TRUE(Remark.Loc);
368 const remarks::RemarkLocation &RL = *Remark.Loc;
369 EXPECT_EQ(checkStr(RL.SourceFilePath, 6), "file.c");
370 EXPECT_EQ(RL.SourceLine, 3U);
371 EXPECT_EQ(RL.SourceColumn, 12U);
372 EXPECT_TRUE(Remark.Hotness);
373 EXPECT_EQ(*Remark.Hotness, 4U);
374 EXPECT_EQ(Remark.Args.size(), 4U);
375
376 unsigned ArgID = 0;
377 for (const remarks::Argument &Arg : Remark.Args) {
378 switch (ArgID) {
379 case 0:
380 EXPECT_EQ(checkStr(Arg.Key, 6), "Callee");
381 EXPECT_EQ(checkStr(Arg.Val, 3), "bar");
382 EXPECT_FALSE(Arg.Loc);
383 break;
384 case 1:
385 EXPECT_EQ(checkStr(Arg.Key, 6), "String");
386 EXPECT_EQ(checkStr(Arg.Val, 26), " will not be inlined into ");
387 EXPECT_FALSE(Arg.Loc);
388 break;
389 case 2: {
390 EXPECT_EQ(checkStr(Arg.Key, 6), "Caller");
391 EXPECT_EQ(checkStr(Arg.Val, 3), "foo");
392 EXPECT_TRUE(Arg.Loc);
393 const remarks::RemarkLocation &RL = *Arg.Loc;
394 EXPECT_EQ(checkStr(RL.SourceFilePath, 6), "file.c");
395 EXPECT_EQ(RL.SourceLine, 2U);
396 EXPECT_EQ(RL.SourceColumn, 0U);
397 break;
398 }
399 case 3:
400 EXPECT_EQ(checkStr(Arg.Key, 6), "String");
401 EXPECT_EQ(checkStr(Arg.Val, 38),
402 " because its definition is unavailable");
403 EXPECT_FALSE(Arg.Loc);
404 break;
405 default:
406 break;
407 }
408 ++ArgID;
409 }
410
411 RemarkOrErr = Parser.getNext();
412 EXPECT_FALSE(errorToBool(RemarkOrErr.takeError()));
413 EXPECT_EQ(*RemarkOrErr, nullptr);
414}
415
416static inline StringRef checkStr(LLVMRemarkStringRef Str,
417 unsigned ExpectedLen) {
418 const char *StrData = LLVMRemarkStringGetData(Str);
419 unsigned StrLen = LLVMRemarkStringGetLen(Str);
420 EXPECT_EQ(StrLen, ExpectedLen);
421 return StringRef(StrData, StrLen);
422}
423
424TEST(YAMLRemarks, ContentsCAPI) {
425 StringRef Buf = "\n"
426 "--- !Missed\n"
427 "Pass: inline\n"
428 "Name: NoDefinition\n"
429 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
430 "Function: foo\n"
431 "Args:\n"
432 " - Callee: bar\n"
433 " - String: ' will not be inlined into '\n"
434 " - Caller: foo\n"
435 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
436 " - String: ' because its definition is unavailable'\n"
437 "\n";
438
439 LLVMRemarkParserRef Parser =
440 LLVMRemarkParserCreateYAML(Buf.data(), Buf.size());
441 LLVMRemarkEntryRef Remark = LLVMRemarkParserGetNext(Parser);
442 EXPECT_FALSE(Remark == nullptr);
443 EXPECT_EQ(LLVMRemarkEntryGetType(Remark), LLVMRemarkTypeMissed);
444 EXPECT_EQ(checkStr(LLVMRemarkEntryGetPassName(Remark), 6), "inline");
445 EXPECT_EQ(checkStr(LLVMRemarkEntryGetRemarkName(Remark), 12), "NoDefinition");
446 EXPECT_EQ(checkStr(LLVMRemarkEntryGetFunctionName(Remark), 3), "foo");
447 LLVMRemarkDebugLocRef DL = LLVMRemarkEntryGetDebugLoc(Remark);
448 EXPECT_EQ(checkStr(LLVMRemarkDebugLocGetSourceFilePath(DL), 6), "file.c");
449 EXPECT_EQ(LLVMRemarkDebugLocGetSourceLine(DL), 3U);
450 EXPECT_EQ(LLVMRemarkDebugLocGetSourceColumn(DL), 12U);
451 EXPECT_EQ(LLVMRemarkEntryGetHotness(Remark), 0U);
452 EXPECT_EQ(LLVMRemarkEntryGetNumArgs(Remark), 4U);
453
454 unsigned ArgID = 0;
455 LLVMRemarkArgRef Arg = LLVMRemarkEntryGetFirstArg(Remark);
456 do {
457 switch (ArgID) {
458 case 0:
459 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "Callee");
460 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 3), "bar");
461 EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr);
462 break;
463 case 1:
464 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "String");
465 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 26),
466 " will not be inlined into ");
467 EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr);
468 break;
469 case 2: {
470 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "Caller");
471 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 3), "foo");
472 LLVMRemarkDebugLocRef DL = LLVMRemarkArgGetDebugLoc(Arg);
473 EXPECT_EQ(checkStr(LLVMRemarkDebugLocGetSourceFilePath(DL), 6), "file.c");
474 EXPECT_EQ(LLVMRemarkDebugLocGetSourceLine(DL), 2U);
475 EXPECT_EQ(LLVMRemarkDebugLocGetSourceColumn(DL), 0U);
476 break;
477 }
478 case 3:
479 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "String");
480 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 38),
481 " because its definition is unavailable");
482 EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr);
483 break;
484 default:
485 break;
486 }
487 ++ArgID;
488 } while ((Arg = LLVMRemarkEntryGetNextArg(Arg, Remark)));
489
490 EXPECT_EQ(LLVMRemarkParserGetNext(Parser), nullptr);
491
492 EXPECT_FALSE(LLVMRemarkParserHasError(Parser));
493 LLVMRemarkParserDispose(Parser);
494}