diff options
author | Francis Visoiu Mistrih <francisvm@yahoo.com> | 2019-03-19 21:11:07 +0000 |
---|---|---|
committer | Francis Visoiu Mistrih <francisvm@yahoo.com> | 2019-03-19 21:11:07 +0000 |
commit | 5a05cc0eebd4834dfee0bc3d0569136e5d6419e1 (patch) | |
tree | 64c3e48690aecfd78832a6ca259560b892d5eaa6 /llvm/unittests/Remarks | |
parent | cc37af7a3631b200b691ba42a47aaab170fea423 (diff) | |
download | bcm5719-llvm-5a05cc0eebd4834dfee0bc3d0569136e5d6419e1.tar.gz bcm5719-llvm-5a05cc0eebd4834dfee0bc3d0569136e5d6419e1.zip |
Reland "[Remarks] Add a new Remark / RemarkParser abstraction"
This adds a Remark class that allows us to share code when working with
remarks.
The C API has been updated to reflect this. Instead of the parser
generating C structs, it's now using a C++ object that is used through
opaque pointers in C. This gives us much more flexibility on what
changes we can make to the internal state of the object and interacts
much better with scenarios where the library is used through dlopen.
* C API updates:
* move from C structs to opaque pointers and functions
* the remark type is now an enum instead of a string
* unit tests updates:
* use mostly the C++ API
* keep one test for the C API
* rename to YAMLRemarksParsingTest
* a typo was fixed: AnalysisFPCompute -> AnalysisFPCommute.
* a new error message was added: "expected a remark tag."
* llvm-opt-report has been updated to use the C++ parser instead of the
C API
Differential Revision: https://reviews.llvm.org/D59049
Original llvm-svn: 356491
llvm-svn: 356519
Diffstat (limited to 'llvm/unittests/Remarks')
-rw-r--r-- | llvm/unittests/Remarks/CMakeLists.txt | 2 | ||||
-rw-r--r-- | llvm/unittests/Remarks/RemarksParsingTest.cpp | 436 | ||||
-rw-r--r-- | llvm/unittests/Remarks/YAMLRemarksParsingTest.cpp | 494 |
3 files changed, 495 insertions, 437 deletions
diff --git a/llvm/unittests/Remarks/CMakeLists.txt b/llvm/unittests/Remarks/CMakeLists.txt index 7d80cf2348d..b7d22b694ef 100644 --- a/llvm/unittests/Remarks/CMakeLists.txt +++ b/llvm/unittests/Remarks/CMakeLists.txt @@ -4,5 +4,5 @@ set(LLVM_LINK_COMPONENTS ) add_llvm_unittest(RemarksTests - RemarksParsingTest.cpp + YAMLRemarksParsingTest.cpp ) diff --git a/llvm/unittests/Remarks/RemarksParsingTest.cpp b/llvm/unittests/Remarks/RemarksParsingTest.cpp deleted file mode 100644 index a167b8318a4..00000000000 --- a/llvm/unittests/Remarks/RemarksParsingTest.cpp +++ /dev/null @@ -1,436 +0,0 @@ -//===- unittest/Support/RemarksParsingTest.cpp - OptTable tests --------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm-c/Remarks.h" -#include "gtest/gtest.h" - -using namespace llvm; - -template <size_t N> bool tryParse(const char (&Buf)[N]) { - LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf, N - 1); - LLVMRemarkEntry *Remark = nullptr; - while (LLVMRemarkEntry *NewRemark = LLVMRemarkParserGetNext(Parser)) { - EXPECT_TRUE(Remark == nullptr); // Only one remark per test. - Remark = NewRemark; - } - EXPECT_TRUE(Remark != nullptr); // We need *exactly* one remark per test. - bool HasError = LLVMRemarkParserHasError(Parser); - LLVMRemarkParserDispose(Parser); - return !HasError; -} - -template <size_t N> -bool parseExpectError(const char (&Buf)[N], const char *Error) { - LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf, N - 1); - LLVMRemarkEntry *Remark = nullptr; - while (LLVMRemarkEntry *NewRemark = LLVMRemarkParserGetNext(Parser)) { - EXPECT_FALSE(NewRemark); - } - EXPECT_TRUE(Remark == nullptr); // We are parsing only one malformed remark. - EXPECT_TRUE(LLVMRemarkParserHasError(Parser)); - bool MatchesError = - StringRef(LLVMRemarkParserGetErrorMessage(Parser)).contains(Error); - LLVMRemarkParserDispose(Parser); - - return MatchesError; -} - -TEST(Remarks, RemarksParsingEmpty) { - StringRef Buf = "\n" - "\n"; - LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf.data(), Buf.size()); - LLVMRemarkEntry *NewRemark = LLVMRemarkParserGetNext(Parser); - EXPECT_TRUE(NewRemark == nullptr); // No remark expected. - EXPECT_TRUE(LLVMRemarkParserHasError(Parser)); - EXPECT_TRUE(StringRef(LLVMRemarkParserGetErrorMessage(Parser)) - .contains("document root is not of mapping type.")); - LLVMRemarkParserDispose(Parser); -} - -TEST(Remarks, RemarksParsingGood) { - EXPECT_TRUE(tryParse("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" - "Function: foo\n" - "Args:\n" - " - Callee: bar\n" - " - String: ' will not be inlined into '\n" - " - Caller: foo\n" - " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" - " - String: ' because its definition is unavailable'\n" - "")); - - // No debug loc should also pass. - EXPECT_TRUE(tryParse("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "Args:\n" - " - Callee: bar\n" - " - String: ' will not be inlined into '\n" - " - Caller: foo\n" - " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" - " - String: ' because its definition is unavailable'\n" - "")); - - // No args is also ok. - EXPECT_TRUE(tryParse("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" - "Function: foo\n" - "")); - - // Different order. - EXPECT_TRUE(tryParse("\n" - "--- !Missed\n" - "DebugLoc: { Line: 3, Column: 12, File: file.c }\n" - "Function: foo\n" - "Name: NoDefinition\n" - "Args:\n" - " - Callee: bar\n" - " - String: ' will not be inlined into '\n" - " - Caller: foo\n" - " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" - " - String: ' because its definition is unavailable'\n" - "Pass: inline\n" - "")); -} - -// Mandatory common part of a remark. -#define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n\n" -// Test all the types. -TEST(Remarks, RemarksParsingTypes) { - // Type: Passed - EXPECT_TRUE(tryParse("--- !Passed" COMMON_REMARK)); - // Type: Missed - EXPECT_TRUE(tryParse("--- !Missed" COMMON_REMARK)); - // Type: Analysis - EXPECT_TRUE(tryParse("--- !Analysis" COMMON_REMARK)); - // Type: AnalysisFPCompute - EXPECT_TRUE(tryParse("--- !AnalysisFPCompute" COMMON_REMARK)); - // Type: AnalysisAliasing - EXPECT_TRUE(tryParse("--- !AnalysisAliasing" COMMON_REMARK)); - // Type: Failure - EXPECT_TRUE(tryParse("--- !Failure" COMMON_REMARK)); -} -#undef COMMON_REMARK - -TEST(Remarks, RemarksParsingMissingFields) { - // No type. - EXPECT_TRUE(parseExpectError("\n" - "---\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "", - "error: Type, Pass, Name or Function missing.")); - // No pass. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "Name: NoDefinition\n" - "Function: foo\n" - "", - "error: Type, Pass, Name or Function missing.")); - // No name. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Function: foo\n" - "", - "error: Type, Pass, Name or Function missing.")); - // No function. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "", - "error: Type, Pass, Name or Function missing.")); - // Debug loc but no file. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "DebugLoc: { Line: 3, Column: 12 }\n" - "", - "DebugLoc node incomplete.")); - // Debug loc but no line. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "DebugLoc: { File: file.c, Column: 12 }\n" - "", - "DebugLoc node incomplete.")); - // Debug loc but no column. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "DebugLoc: { File: file.c, Line: 3 }\n" - "", - "DebugLoc node incomplete.")); -} - -TEST(Remarks, RemarksParsingWrongTypes) { - // Wrong debug loc type. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "DebugLoc: foo\n" - "", - "expected a value of mapping type.")); - // Wrong line type. - EXPECT_TRUE( - parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "DebugLoc: { File: file.c, Line: b, Column: 12 }\n" - "", - "expected a value of integer type.")); - // Wrong column type. - EXPECT_TRUE( - parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "DebugLoc: { File: file.c, Line: 3, Column: c }\n" - "", - "expected a value of integer type.")); - // Wrong args type. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "Args: foo\n" - "", - "wrong value type for key.")); - // Wrong key type. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "{ A: a }: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "", - "key is not a string.")); - // Debug loc with unknown entry. - EXPECT_TRUE( - parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "DebugLoc: { File: file.c, Column: 12, Unknown: 12 }\n" - "", - "unknown entry in DebugLoc map.")); - // Unknown entry. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "Unknown: inline\n" - "", - "unknown key.")); - // Not a scalar. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "Pass: { File: a, Line: 1, Column: 2 }\n" - "Name: NoDefinition\n" - "Function: foo\n" - "", - "expected a value of scalar type.")); - // Not a string file in debug loc. - EXPECT_TRUE( - parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "DebugLoc: { File: { a: b }, Column: 12, Line: 12 }\n" - "", - "expected a value of scalar type.")); - // Not a integer column in debug loc. - EXPECT_TRUE(parseExpectError( - "\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "DebugLoc: { File: file.c, Column: { a: b }, Line: 12 }\n" - "", - "expected a value of scalar type.")); - // Not a integer line in debug loc. - EXPECT_TRUE(parseExpectError( - "\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n" - "", - "expected a value of scalar type.")); - // Not a mapping type value for args. - EXPECT_TRUE(parseExpectError( - "\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n" - "", - "expected a value of scalar type.")); -} - -TEST(Remarks, RemarksParsingWrongArgs) { - // Multiple debug locs per arg. - EXPECT_TRUE( - parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "Args:\n" - " - Str: string\n" - " DebugLoc: { File: a, Line: 1, Column: 2 }\n" - " DebugLoc: { File: a, Line: 1, Column: 2 }\n" - "", - "only one DebugLoc entry is allowed per argument.")); - // Multiple strings per arg. - EXPECT_TRUE( - parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "Args:\n" - " - Str: string\n" - " Str2: string\n" - " DebugLoc: { File: a, Line: 1, Column: 2 }\n" - "", - "only one string entry is allowed per argument.")); - // No arg value. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "Args:\n" - " - Callee: ''\n" - " - DebugLoc: { File: a, Line: 1, Column: 2 }\n" - "", - "argument value is missing.")); - // No arg value. - EXPECT_TRUE(parseExpectError("\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "Function: foo\n" - "Args:\n" - " - DebugLoc: { File: a, Line: 1, Column: 2 }\n" - "", - "argument key is missing.")); -} - -TEST(Remarks, RemarksGoodStruct) { - StringRef Buf = "\n" - "--- !Missed\n" - "Pass: inline\n" - "Name: NoDefinition\n" - "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" - "Function: foo\n" - "Args:\n" - " - Callee: bar\n" - " - String: ' will not be inlined into '\n" - " - Caller: foo\n" - " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" - " - String: ' because its definition is unavailable'\n" - "\n"; - - LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf.data(), Buf.size()); - LLVMRemarkEntry *Remark = LLVMRemarkParserGetNext(Parser); - EXPECT_FALSE(Remark == nullptr); - EXPECT_EQ(StringRef(Remark->RemarkType.Str, 7), "!Missed"); - EXPECT_EQ(Remark->RemarkType.Len, 7U); - EXPECT_EQ(StringRef(Remark->PassName.Str, 6), "inline"); - EXPECT_EQ(Remark->PassName.Len, 6U); - EXPECT_EQ(StringRef(Remark->RemarkName.Str, 12), "NoDefinition"); - EXPECT_EQ(Remark->RemarkName.Len, 12U); - EXPECT_EQ(StringRef(Remark->FunctionName.Str, 3), "foo"); - EXPECT_EQ(Remark->FunctionName.Len, 3U); - EXPECT_EQ(StringRef(Remark->DebugLoc.SourceFile.Str, 6), "file.c"); - EXPECT_EQ(Remark->DebugLoc.SourceFile.Len, 6U); - EXPECT_EQ(Remark->DebugLoc.SourceLineNumber, 3U); - EXPECT_EQ(Remark->DebugLoc.SourceColumnNumber, 12U); - EXPECT_EQ(Remark->Hotness, 0U); - EXPECT_EQ(Remark->NumArgs, 4U); - // Arg 0 - { - LLVMRemarkArg &Arg = Remark->Args[0]; - EXPECT_EQ(StringRef(Arg.Key.Str, 6), "Callee"); - EXPECT_EQ(Arg.Key.Len, 6U); - EXPECT_EQ(StringRef(Arg.Value.Str, 3), "bar"); - EXPECT_EQ(Arg.Value.Len, 3U); - EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), ""); - EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U); - EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U); - EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U); - } - // Arg 1 - { - LLVMRemarkArg &Arg = Remark->Args[1]; - EXPECT_EQ(StringRef(Arg.Key.Str, 6), "String"); - EXPECT_EQ(Arg.Key.Len, 6U); - EXPECT_EQ(StringRef(Arg.Value.Str, 26), " will not be inlined into "); - EXPECT_EQ(Arg.Value.Len, 26U); - EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), ""); - EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U); - EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U); - EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U); - } - // Arg 2 - { - LLVMRemarkArg &Arg = Remark->Args[2]; - EXPECT_EQ(StringRef(Arg.Key.Str, 6), "Caller"); - EXPECT_EQ(Arg.Key.Len, 6U); - EXPECT_EQ(StringRef(Arg.Value.Str, 3), "foo"); - EXPECT_EQ(Arg.Value.Len, 3U); - EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 6), "file.c"); - EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 6U); - EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 2U); - EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U); - } - // Arg 3 - { - LLVMRemarkArg &Arg = Remark->Args[3]; - EXPECT_EQ(StringRef(Arg.Key.Str, 6), "String"); - EXPECT_EQ(Arg.Key.Len, 6U); - EXPECT_EQ(StringRef(Arg.Value.Str, 38), - " because its definition is unavailable"); - EXPECT_EQ(Arg.Value.Len, 38U); - EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), ""); - EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U); - EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U); - EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U); - } - - EXPECT_EQ(LLVMRemarkParserGetNext(Parser), nullptr); - - EXPECT_FALSE(LLVMRemarkParserHasError(Parser)); - LLVMRemarkParserDispose(Parser); -} diff --git a/llvm/unittests/Remarks/YAMLRemarksParsingTest.cpp b/llvm/unittests/Remarks/YAMLRemarksParsingTest.cpp new file mode 100644 index 00000000000..36dbb0c9518 --- /dev/null +++ b/llvm/unittests/Remarks/YAMLRemarksParsingTest.cpp @@ -0,0 +1,494 @@ +//===- unittest/Support/YAMLRemarksParsingTest.cpp - OptTable tests -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm-c/Remarks.h" +#include "llvm/Remarks/Remark.h" +#include "llvm/Remarks/RemarkParser.h" +#include "gtest/gtest.h" + +using namespace llvm; + +template <size_t N> void parseGood(const char (&Buf)[N]) { + remarks::Parser Parser({Buf, N - 1}); + Expected<const remarks::Remark *> Remark = Parser.getNext(); + EXPECT_FALSE(errorToBool(Remark.takeError())); // Check for parsing errors. + EXPECT_TRUE(*Remark != nullptr); // At least one remark. + Remark = Parser.getNext(); + EXPECT_FALSE(errorToBool(Remark.takeError())); // Check for parsing errors. + EXPECT_TRUE(*Remark == nullptr); // Check that there are no more remarks. +} + +template <size_t N> +bool parseExpectError(const char (&Buf)[N], const char *Error) { + remarks::Parser Parser({Buf, N - 1}); + Expected<const remarks::Remark *> Remark = Parser.getNext(); + EXPECT_FALSE(Remark); // Expect an error here. + + std::string ErrorStr; + raw_string_ostream Stream(ErrorStr); + handleAllErrors(Remark.takeError(), + [&](const ErrorInfoBase &EIB) { EIB.log(Stream); }); + return StringRef(Stream.str()).contains(Error); +} + +TEST(YAMLRemarks, ParsingEmpty) { + EXPECT_TRUE(parseExpectError("\n\n", "document root is not of mapping type.")); +} + +TEST(YAMLRemarks, ParsingNotYAML) { + EXPECT_TRUE( + parseExpectError("\x01\x02\x03\x04\x05\x06", "not a valid YAML file.")); +} + +TEST(YAMLRemarks, ParsingGood) { + parseGood("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" + "Function: foo\n" + "Args:\n" + " - Callee: bar\n" + " - String: ' will not be inlined into '\n" + " - Caller: foo\n" + " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" + " - String: ' because its definition is unavailable'\n" + ""); + + // No debug loc should also pass. + parseGood("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "Args:\n" + " - Callee: bar\n" + " - String: ' will not be inlined into '\n" + " - Caller: foo\n" + " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" + " - String: ' because its definition is unavailable'\n" + ""); + + // No args is also ok. + parseGood("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" + "Function: foo\n" + ""); + + // Different order. + parseGood("\n" + "--- !Missed\n" + "DebugLoc: { Line: 3, Column: 12, File: file.c }\n" + "Function: foo\n" + "Name: NoDefinition\n" + "Args:\n" + " - Callee: bar\n" + " - String: ' will not be inlined into '\n" + " - Caller: foo\n" + " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" + " - String: ' because its definition is unavailable'\n" + "Pass: inline\n" + ""); +} + +// Mandatory common part of a remark. +#define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n\n" +// Test all the types. +TEST(YAMLRemarks, ParsingTypes) { + // Type: Passed + parseGood("--- !Passed" COMMON_REMARK); + // Type: Missed + parseGood("--- !Missed" COMMON_REMARK); + // Type: Analysis + parseGood("--- !Analysis" COMMON_REMARK); + // Type: AnalysisFPCommute + parseGood("--- !AnalysisFPCommute" COMMON_REMARK); + // Type: AnalysisAliasing + parseGood("--- !AnalysisAliasing" COMMON_REMARK); + // Type: Failure + parseGood("--- !Failure" COMMON_REMARK); +} +#undef COMMON_REMARK + +TEST(YAMLRemarks, ParsingMissingFields) { + // No type. + EXPECT_TRUE(parseExpectError("\n" + "---\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "", + "expected a remark tag.")); + // No pass. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Name: NoDefinition\n" + "Function: foo\n" + "", + "Type, Pass, Name or Function missing.")); + // No name. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Function: foo\n" + "", + "Type, Pass, Name or Function missing.")); + // No function. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "", + "Type, Pass, Name or Function missing.")); + // Debug loc but no file. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { Line: 3, Column: 12 }\n" + "", + "DebugLoc node incomplete.")); + // Debug loc but no line. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Column: 12 }\n" + "", + "DebugLoc node incomplete.")); + // Debug loc but no column. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Line: 3 }\n" + "", + "DebugLoc node incomplete.")); +} + +TEST(YAMLRemarks, ParsingWrongTypes) { + // Wrong debug loc type. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: foo\n" + "", + "expected a value of mapping type.")); + // Wrong line type. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Line: b, Column: 12 }\n" + "", + "expected a value of integer type.")); + // Wrong column type. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Line: 3, Column: c }\n" + "", + "expected a value of integer type.")); + // Wrong args type. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "Args: foo\n" + "", + "wrong value type for key.")); + // Wrong key type. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "{ A: a }: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "", + "key is not a string.")); + // Debug loc with unknown entry. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Column: 12, Unknown: 12 }\n" + "", + "unknown entry in DebugLoc map.")); + // Unknown entry. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Unknown: inline\n" + "", + "unknown key.")); + // Not a scalar. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: { File: a, Line: 1, Column: 2 }\n" + "Name: NoDefinition\n" + "Function: foo\n" + "", + "expected a value of scalar type.")); + // Not a string file in debug loc. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: { a: b }, Column: 12, Line: 12 }\n" + "", + "expected a value of scalar type.")); + // Not a integer column in debug loc. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Column: { a: b }, Line: 12 }\n" + "", + "expected a value of scalar type.")); + // Not a integer line in debug loc. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n" + "", + "expected a value of scalar type.")); + // Not a mapping type value for args. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n" + "", + "expected a value of scalar type.")); +} + +TEST(YAMLRemarks, ParsingWrongArgs) { + // Multiple debug locs per arg. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "Args:\n" + " - Str: string\n" + " DebugLoc: { File: a, Line: 1, Column: 2 }\n" + " DebugLoc: { File: a, Line: 1, Column: 2 }\n" + "", + "only one DebugLoc entry is allowed per argument.")); + // Multiple strings per arg. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "Args:\n" + " - Str: string\n" + " Str2: string\n" + " DebugLoc: { File: a, Line: 1, Column: 2 }\n" + "", + "only one string entry is allowed per argument.")); + // No arg value. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "Args:\n" + " - Callee: ''\n" + " - DebugLoc: { File: a, Line: 1, Column: 2 }\n" + "", + "argument value is missing.")); + // No arg value. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "Args:\n" + " - DebugLoc: { File: a, Line: 1, Column: 2 }\n" + "", + "argument key is missing.")); +} + +static inline StringRef checkStr(StringRef Str, unsigned ExpectedLen) { + const char *StrData = Str.data(); + unsigned StrLen = Str.size(); + EXPECT_EQ(StrLen, ExpectedLen); + return StringRef(StrData, StrLen); +} + +TEST(YAMLRemarks, Contents) { + StringRef Buf = "\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" + "Function: foo\n" + "Hotness: 4\n" + "Args:\n" + " - Callee: bar\n" + " - String: ' will not be inlined into '\n" + " - Caller: foo\n" + " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" + " - String: ' because its definition is unavailable'\n" + "\n"; + + remarks::Parser Parser(Buf); + Expected<const remarks::Remark *> RemarkOrErr = Parser.getNext(); + EXPECT_FALSE(errorToBool(RemarkOrErr.takeError())); + EXPECT_TRUE(*RemarkOrErr != nullptr); + + const remarks::Remark &Remark = **RemarkOrErr; + EXPECT_EQ(Remark.RemarkType, remarks::Type::Missed); + EXPECT_EQ(checkStr(Remark.PassName, 6), "inline"); + EXPECT_EQ(checkStr(Remark.RemarkName, 12), "NoDefinition"); + EXPECT_EQ(checkStr(Remark.FunctionName, 3), "foo"); + EXPECT_TRUE(Remark.Loc); + const remarks::RemarkLocation &RL = *Remark.Loc; + EXPECT_EQ(checkStr(RL.SourceFilePath, 6), "file.c"); + EXPECT_EQ(RL.SourceLine, 3U); + EXPECT_EQ(RL.SourceColumn, 12U); + EXPECT_TRUE(Remark.Hotness); + EXPECT_EQ(*Remark.Hotness, 4U); + EXPECT_EQ(Remark.Args.size(), 4U); + + unsigned ArgID = 0; + for (const remarks::Argument &Arg : Remark.Args) { + switch (ArgID) { + case 0: + EXPECT_EQ(checkStr(Arg.Key, 6), "Callee"); + EXPECT_EQ(checkStr(Arg.Val, 3), "bar"); + EXPECT_FALSE(Arg.Loc); + break; + case 1: + EXPECT_EQ(checkStr(Arg.Key, 6), "String"); + EXPECT_EQ(checkStr(Arg.Val, 26), " will not be inlined into "); + EXPECT_FALSE(Arg.Loc); + break; + case 2: { + EXPECT_EQ(checkStr(Arg.Key, 6), "Caller"); + EXPECT_EQ(checkStr(Arg.Val, 3), "foo"); + EXPECT_TRUE(Arg.Loc); + const remarks::RemarkLocation &RL = *Arg.Loc; + EXPECT_EQ(checkStr(RL.SourceFilePath, 6), "file.c"); + EXPECT_EQ(RL.SourceLine, 2U); + EXPECT_EQ(RL.SourceColumn, 0U); + break; + } + case 3: + EXPECT_EQ(checkStr(Arg.Key, 6), "String"); + EXPECT_EQ(checkStr(Arg.Val, 38), + " because its definition is unavailable"); + EXPECT_FALSE(Arg.Loc); + break; + default: + break; + } + ++ArgID; + } + + RemarkOrErr = Parser.getNext(); + EXPECT_FALSE(errorToBool(RemarkOrErr.takeError())); + EXPECT_EQ(*RemarkOrErr, nullptr); +} + +static inline StringRef checkStr(LLVMRemarkStringRef Str, + unsigned ExpectedLen) { + const char *StrData = LLVMRemarkStringGetData(Str); + unsigned StrLen = LLVMRemarkStringGetLen(Str); + EXPECT_EQ(StrLen, ExpectedLen); + return StringRef(StrData, StrLen); +} + +TEST(YAMLRemarks, ContentsCAPI) { + StringRef Buf = "\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" + "Function: foo\n" + "Args:\n" + " - Callee: bar\n" + " - String: ' will not be inlined into '\n" + " - Caller: foo\n" + " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" + " - String: ' because its definition is unavailable'\n" + "\n"; + + LLVMRemarkParserRef Parser = + LLVMRemarkParserCreateYAML(Buf.data(), Buf.size()); + LLVMRemarkEntryRef Remark = LLVMRemarkParserGetNext(Parser); + EXPECT_FALSE(Remark == nullptr); + EXPECT_EQ(LLVMRemarkEntryGetType(Remark), LLVMRemarkTypeMissed); + EXPECT_EQ(checkStr(LLVMRemarkEntryGetPassName(Remark), 6), "inline"); + EXPECT_EQ(checkStr(LLVMRemarkEntryGetRemarkName(Remark), 12), "NoDefinition"); + EXPECT_EQ(checkStr(LLVMRemarkEntryGetFunctionName(Remark), 3), "foo"); + LLVMRemarkDebugLocRef DL = LLVMRemarkEntryGetDebugLoc(Remark); + EXPECT_EQ(checkStr(LLVMRemarkDebugLocGetSourceFilePath(DL), 6), "file.c"); + EXPECT_EQ(LLVMRemarkDebugLocGetSourceLine(DL), 3U); + EXPECT_EQ(LLVMRemarkDebugLocGetSourceColumn(DL), 12U); + EXPECT_EQ(LLVMRemarkEntryGetHotness(Remark), 0U); + EXPECT_EQ(LLVMRemarkEntryGetNumArgs(Remark), 4U); + + unsigned ArgID = 0; + LLVMRemarkArgRef Arg = LLVMRemarkEntryGetFirstArg(Remark); + do { + switch (ArgID) { + case 0: + EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "Callee"); + EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 3), "bar"); + EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr); + break; + case 1: + EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "String"); + EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 26), + " will not be inlined into "); + EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr); + break; + case 2: { + EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "Caller"); + EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 3), "foo"); + LLVMRemarkDebugLocRef DL = LLVMRemarkArgGetDebugLoc(Arg); + EXPECT_EQ(checkStr(LLVMRemarkDebugLocGetSourceFilePath(DL), 6), "file.c"); + EXPECT_EQ(LLVMRemarkDebugLocGetSourceLine(DL), 2U); + EXPECT_EQ(LLVMRemarkDebugLocGetSourceColumn(DL), 0U); + break; + } + case 3: + EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "String"); + EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 38), + " because its definition is unavailable"); + EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr); + break; + default: + break; + } + ++ArgID; + } while ((Arg = LLVMRemarkEntryGetNextArg(Arg, Remark))); + + EXPECT_EQ(LLVMRemarkParserGetNext(Parser), nullptr); + + EXPECT_FALSE(LLVMRemarkParserHasError(Parser)); + LLVMRemarkParserDispose(Parser); +} |