forked from OSchip/llvm-project
433 lines
13 KiB
C++
433 lines
13 KiB
C++
//===- unittest/Support/OptRemarksParsingTest.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/OptRemarks.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
template <size_t N> bool tryParse(const char (&Buf)[N]) {
|
|
LLVMOptRemarkParserRef Parser = LLVMOptRemarkParserCreate(Buf, N - 1);
|
|
LLVMOptRemarkEntry *Remark = nullptr;
|
|
while (LLVMOptRemarkEntry *NewRemark = LLVMOptRemarkParserGetNext(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 = LLVMOptRemarkParserHasError(Parser);
|
|
LLVMOptRemarkParserDispose(Parser);
|
|
return !HasError;
|
|
}
|
|
|
|
template <size_t N>
|
|
bool parseExpectError(const char (&Buf)[N], const char *Error) {
|
|
LLVMOptRemarkParserRef Parser = LLVMOptRemarkParserCreate(Buf, N - 1);
|
|
LLVMOptRemarkEntry *Remark = nullptr;
|
|
while (LLVMOptRemarkEntry *NewRemark = LLVMOptRemarkParserGetNext(Parser)) {
|
|
EXPECT_FALSE(NewRemark);
|
|
}
|
|
EXPECT_TRUE(Remark == nullptr); // We are parsing only one malformed remark.
|
|
EXPECT_TRUE(LLVMOptRemarkParserHasError(Parser));
|
|
bool MatchesError =
|
|
StringRef(LLVMOptRemarkParserGetErrorMessage(Parser)).contains(Error);
|
|
LLVMOptRemarkParserDispose(Parser);
|
|
|
|
return MatchesError;
|
|
}
|
|
|
|
TEST(OptRemarks, OptRemarksParsingEmpty) {
|
|
StringRef Buf = "\n"
|
|
"\n";
|
|
LLVMOptRemarkParserRef Parser =
|
|
LLVMOptRemarkParserCreate(Buf.data(), Buf.size());
|
|
LLVMOptRemarkEntry *NewRemark = LLVMOptRemarkParserGetNext(Parser);
|
|
EXPECT_TRUE(NewRemark == nullptr); // No remark expected.
|
|
EXPECT_TRUE(LLVMOptRemarkParserHasError(Parser));
|
|
EXPECT_TRUE(StringRef(LLVMOptRemarkParserGetErrorMessage(Parser))
|
|
.contains("document root is not of mapping type."));
|
|
LLVMOptRemarkParserDispose(Parser);
|
|
}
|
|
|
|
TEST(OptRemarks, OptRemarksParsingGood) {
|
|
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(OptRemarks, OptRemarksParsingTypes) {
|
|
// 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(OptRemarks, OptRemarksParsingMissingFields) {
|
|
// 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(OptRemarks, OptRemarksParsingWrongTypes) {
|
|
// 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(OptRemarks, OptRemarksParsingWrongArgs) {
|
|
// 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(OptRemarks, OptRemarksGoodStruct) {
|
|
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";
|
|
|
|
LLVMOptRemarkParserRef Parser =
|
|
LLVMOptRemarkParserCreate(Buf.data(), Buf.size());
|
|
LLVMOptRemarkEntry *Remark = LLVMOptRemarkParserGetNext(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
|
|
{
|
|
LLVMOptRemarkArg &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
|
|
{
|
|
LLVMOptRemarkArg &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
|
|
{
|
|
LLVMOptRemarkArg &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
|
|
{
|
|
LLVMOptRemarkArg &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(LLVMOptRemarkParserGetNext(Parser), nullptr);
|
|
|
|
EXPECT_FALSE(LLVMOptRemarkParserHasError(Parser));
|
|
LLVMOptRemarkParserDispose(Parser);
|
|
}
|