2019-03-20 05:11:07 +08:00
|
|
|
//===- 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]) {
|
2019-07-16 23:25:05 +08:00
|
|
|
Expected<std::unique_ptr<remarks::Parser>> MaybeParser =
|
|
|
|
remarks::createRemarkParser(remarks::Format::YAML, {Buf, N - 1});
|
|
|
|
EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
|
|
|
|
EXPECT_TRUE(*MaybeParser != nullptr);
|
|
|
|
|
|
|
|
remarks::Parser &Parser = **MaybeParser;
|
|
|
|
Expected<std::unique_ptr<remarks::Remark>> Remark = Parser.next();
|
2019-03-20 05:11:07 +08:00
|
|
|
EXPECT_FALSE(errorToBool(Remark.takeError())); // Check for parsing errors.
|
|
|
|
EXPECT_TRUE(*Remark != nullptr); // At least one remark.
|
2019-07-16 23:25:05 +08:00
|
|
|
Remark = Parser.next();
|
|
|
|
Error E = Remark.takeError();
|
|
|
|
EXPECT_TRUE(E.isA<remarks::EndOfFileError>());
|
|
|
|
EXPECT_TRUE(errorToBool(std::move(E))); // Check for parsing errors.
|
2019-03-20 05:11:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <size_t N>
|
|
|
|
bool parseExpectError(const char (&Buf)[N], const char *Error) {
|
2019-07-16 23:25:05 +08:00
|
|
|
Expected<std::unique_ptr<remarks::Parser>> MaybeParser =
|
|
|
|
remarks::createRemarkParser(remarks::Format::YAML, {Buf, N - 1});
|
|
|
|
EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
|
|
|
|
EXPECT_TRUE(*MaybeParser != nullptr);
|
|
|
|
|
|
|
|
remarks::Parser &Parser = **MaybeParser;
|
|
|
|
Expected<std::unique_ptr<remarks::Remark>> Remark = Parser.next();
|
|
|
|
EXPECT_FALSE(Remark); // Check for parsing errors.
|
2019-03-20 05:11:07 +08:00
|
|
|
|
|
|
|
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(
|
2019-07-16 23:25:05 +08:00
|
|
|
parseExpectError("\x01\x02\x03\x04\x05\x06", "Got empty plain scalar"));
|
2019-03-20 05:11:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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"
|
|
|
|
" - 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";
|
|
|
|
|
2019-07-16 23:25:05 +08:00
|
|
|
Expected<std::unique_ptr<remarks::Parser>> MaybeParser =
|
|
|
|
remarks::createRemarkParser(remarks::Format::YAML, Buf);
|
|
|
|
EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
|
|
|
|
EXPECT_TRUE(*MaybeParser != nullptr);
|
|
|
|
|
|
|
|
remarks::Parser &Parser = **MaybeParser;
|
|
|
|
Expected<std::unique_ptr<remarks::Remark>> MaybeRemark = Parser.next();
|
|
|
|
EXPECT_FALSE(
|
|
|
|
errorToBool(MaybeRemark.takeError())); // Check for parsing errors.
|
|
|
|
EXPECT_TRUE(*MaybeRemark != nullptr); // At least one remark.
|
2019-03-20 05:11:07 +08:00
|
|
|
|
2019-07-16 23:25:05 +08:00
|
|
|
const remarks::Remark &Remark = **MaybeRemark;
|
2019-03-20 05:11:07 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-07-16 23:25:05 +08:00
|
|
|
MaybeRemark = Parser.next();
|
|
|
|
Error E = MaybeRemark.takeError();
|
|
|
|
EXPECT_TRUE(E.isA<remarks::EndOfFileError>());
|
|
|
|
EXPECT_TRUE(errorToBool(std::move(E))); // Check for parsing errors.
|
2019-03-20 05:11:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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)));
|
|
|
|
|
2019-07-16 23:25:05 +08:00
|
|
|
LLVMRemarkEntryDispose(Remark);
|
|
|
|
|
2019-03-20 05:11:07 +08:00
|
|
|
EXPECT_EQ(LLVMRemarkParserGetNext(Parser), nullptr);
|
|
|
|
|
|
|
|
EXPECT_FALSE(LLVMRemarkParserHasError(Parser));
|
|
|
|
LLVMRemarkParserDispose(Parser);
|
|
|
|
}
|
[Remarks] Add string deduplication using a string table
* Add support for uniquing strings in the remark streamer and emitting the string table in the remarks section.
* Add parsing support for the string table in the RemarkParser.
From this remark:
```
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: 'test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c',
Line: 7, Column: 3 }
Function: printArgsNoRet
Args:
- Callee: printf
- String: ' will not be inlined into '
- Caller: printArgsNoRet
DebugLoc: { File: 'test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c',
Line: 6, Column: 0 }
- String: ' because its definition is unavailable'
...
```
to:
```
--- !Missed
Pass: 0
Name: 1
DebugLoc: { File: 3, Line: 7, Column: 3 }
Function: 2
Args:
- Callee: 4
- String: 5
- Caller: 2
DebugLoc: { File: 3, Line: 6, Column: 0 }
- String: 6
...
```
And the string table in the .remarks/__remarks section containing:
```
inline\0NoDefinition\0printArgsNoRet\0
test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c\0printf\0
will not be inlined into \0 because its definition is unavailable\0
```
This is mostly supposed to be used for testing purposes, but it gives us
a 2x reduction in the remark size, and is an incremental change for the
updates to the remarks file format.
Differential Revision: https://reviews.llvm.org/D60227
llvm-svn: 359050
2019-04-24 08:06:24 +08:00
|
|
|
|
|
|
|
TEST(YAMLRemarks, ContentsStrTab) {
|
|
|
|
StringRef Buf = "\n"
|
|
|
|
"--- !Missed\n"
|
|
|
|
"Pass: 0\n"
|
|
|
|
"Name: 1\n"
|
|
|
|
"DebugLoc: { File: 2, Line: 3, Column: 12 }\n"
|
|
|
|
"Function: 3\n"
|
|
|
|
"Hotness: 4\n"
|
|
|
|
"Args:\n"
|
|
|
|
" - Callee: 5\n"
|
|
|
|
" - String: 7\n"
|
|
|
|
" - Caller: 3\n"
|
|
|
|
" DebugLoc: { File: 2, Line: 2, Column: 0 }\n"
|
|
|
|
" - String: 8\n"
|
|
|
|
"\n";
|
|
|
|
|
|
|
|
StringRef StrTabBuf =
|
|
|
|
StringRef("inline\0NoDefinition\0file.c\0foo\0Callee\0bar\0String\0 "
|
|
|
|
"will not be inlined into \0 because its definition is "
|
|
|
|
"unavailable",
|
|
|
|
115);
|
|
|
|
|
2019-07-04 08:30:58 +08:00
|
|
|
remarks::ParsedStringTable StrTab(StrTabBuf);
|
2019-07-16 23:25:05 +08:00
|
|
|
Expected<std::unique_ptr<remarks::Parser>> MaybeParser =
|
2019-07-24 04:42:46 +08:00
|
|
|
remarks::createRemarkParser(remarks::Format::YAMLStrTab, Buf, StrTab);
|
2019-07-16 23:25:05 +08:00
|
|
|
EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
|
|
|
|
EXPECT_TRUE(*MaybeParser != nullptr);
|
|
|
|
|
|
|
|
remarks::Parser &Parser = **MaybeParser;
|
|
|
|
Expected<std::unique_ptr<remarks::Remark>> MaybeRemark = Parser.next();
|
|
|
|
EXPECT_FALSE(
|
|
|
|
errorToBool(MaybeRemark.takeError())); // Check for parsing errors.
|
|
|
|
EXPECT_TRUE(*MaybeRemark != nullptr); // At least one remark.
|
|
|
|
|
|
|
|
const remarks::Remark &Remark = **MaybeRemark;
|
[Remarks] Add string deduplication using a string table
* Add support for uniquing strings in the remark streamer and emitting the string table in the remarks section.
* Add parsing support for the string table in the RemarkParser.
From this remark:
```
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: 'test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c',
Line: 7, Column: 3 }
Function: printArgsNoRet
Args:
- Callee: printf
- String: ' will not be inlined into '
- Caller: printArgsNoRet
DebugLoc: { File: 'test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c',
Line: 6, Column: 0 }
- String: ' because its definition is unavailable'
...
```
to:
```
--- !Missed
Pass: 0
Name: 1
DebugLoc: { File: 3, Line: 7, Column: 3 }
Function: 2
Args:
- Callee: 4
- String: 5
- Caller: 2
DebugLoc: { File: 3, Line: 6, Column: 0 }
- String: 6
...
```
And the string table in the .remarks/__remarks section containing:
```
inline\0NoDefinition\0printArgsNoRet\0
test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c\0printf\0
will not be inlined into \0 because its definition is unavailable\0
```
This is mostly supposed to be used for testing purposes, but it gives us
a 2x reduction in the remark size, and is an incremental change for the
updates to the remarks file format.
Differential Revision: https://reviews.llvm.org/D60227
llvm-svn: 359050
2019-04-24 08:06:24 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-07-16 23:25:05 +08:00
|
|
|
MaybeRemark = Parser.next();
|
|
|
|
Error E = MaybeRemark.takeError();
|
|
|
|
EXPECT_TRUE(E.isA<remarks::EndOfFileError>());
|
|
|
|
EXPECT_TRUE(errorToBool(std::move(E))); // Check for parsing errors.
|
[Remarks] Add string deduplication using a string table
* Add support for uniquing strings in the remark streamer and emitting the string table in the remarks section.
* Add parsing support for the string table in the RemarkParser.
From this remark:
```
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: 'test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c',
Line: 7, Column: 3 }
Function: printArgsNoRet
Args:
- Callee: printf
- String: ' will not be inlined into '
- Caller: printArgsNoRet
DebugLoc: { File: 'test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c',
Line: 6, Column: 0 }
- String: ' because its definition is unavailable'
...
```
to:
```
--- !Missed
Pass: 0
Name: 1
DebugLoc: { File: 3, Line: 7, Column: 3 }
Function: 2
Args:
- Callee: 4
- String: 5
- Caller: 2
DebugLoc: { File: 3, Line: 6, Column: 0 }
- String: 6
...
```
And the string table in the .remarks/__remarks section containing:
```
inline\0NoDefinition\0printArgsNoRet\0
test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c\0printf\0
will not be inlined into \0 because its definition is unavailable\0
```
This is mostly supposed to be used for testing purposes, but it gives us
a 2x reduction in the remark size, and is an incremental change for the
updates to the remarks file format.
Differential Revision: https://reviews.llvm.org/D60227
llvm-svn: 359050
2019-04-24 08:06:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(YAMLRemarks, ParsingBadStringTableIndex) {
|
|
|
|
StringRef Buf = "\n"
|
|
|
|
"--- !Missed\n"
|
|
|
|
"Pass: 50\n"
|
|
|
|
"\n";
|
|
|
|
|
|
|
|
StringRef StrTabBuf = StringRef("inline");
|
|
|
|
|
2019-07-04 08:30:58 +08:00
|
|
|
remarks::ParsedStringTable StrTab(StrTabBuf);
|
2019-07-16 23:25:05 +08:00
|
|
|
Expected<std::unique_ptr<remarks::Parser>> MaybeParser =
|
2019-07-24 04:42:46 +08:00
|
|
|
remarks::createRemarkParser(remarks::Format::YAMLStrTab, Buf, StrTab);
|
2019-07-16 23:25:05 +08:00
|
|
|
EXPECT_FALSE(errorToBool(MaybeParser.takeError()));
|
|
|
|
EXPECT_TRUE(*MaybeParser != nullptr);
|
|
|
|
|
|
|
|
remarks::Parser &Parser = **MaybeParser;
|
|
|
|
Expected<std::unique_ptr<remarks::Remark>> MaybeRemark = Parser.next();
|
|
|
|
EXPECT_FALSE(MaybeRemark); // Expect an error here.
|
[Remarks] Add string deduplication using a string table
* Add support for uniquing strings in the remark streamer and emitting the string table in the remarks section.
* Add parsing support for the string table in the RemarkParser.
From this remark:
```
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: 'test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c',
Line: 7, Column: 3 }
Function: printArgsNoRet
Args:
- Callee: printf
- String: ' will not be inlined into '
- Caller: printArgsNoRet
DebugLoc: { File: 'test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c',
Line: 6, Column: 0 }
- String: ' because its definition is unavailable'
...
```
to:
```
--- !Missed
Pass: 0
Name: 1
DebugLoc: { File: 3, Line: 7, Column: 3 }
Function: 2
Args:
- Callee: 4
- String: 5
- Caller: 2
DebugLoc: { File: 3, Line: 6, Column: 0 }
- String: 6
...
```
And the string table in the .remarks/__remarks section containing:
```
inline\0NoDefinition\0printArgsNoRet\0
test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c\0printf\0
will not be inlined into \0 because its definition is unavailable\0
```
This is mostly supposed to be used for testing purposes, but it gives us
a 2x reduction in the remark size, and is an incremental change for the
updates to the remarks file format.
Differential Revision: https://reviews.llvm.org/D60227
llvm-svn: 359050
2019-04-24 08:06:24 +08:00
|
|
|
|
|
|
|
std::string ErrorStr;
|
|
|
|
raw_string_ostream Stream(ErrorStr);
|
2019-07-16 23:25:05 +08:00
|
|
|
handleAllErrors(MaybeRemark.takeError(),
|
[Remarks] Add string deduplication using a string table
* Add support for uniquing strings in the remark streamer and emitting the string table in the remarks section.
* Add parsing support for the string table in the RemarkParser.
From this remark:
```
--- !Missed
Pass: inline
Name: NoDefinition
DebugLoc: { File: 'test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c',
Line: 7, Column: 3 }
Function: printArgsNoRet
Args:
- Callee: printf
- String: ' will not be inlined into '
- Caller: printArgsNoRet
DebugLoc: { File: 'test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c',
Line: 6, Column: 0 }
- String: ' because its definition is unavailable'
...
```
to:
```
--- !Missed
Pass: 0
Name: 1
DebugLoc: { File: 3, Line: 7, Column: 3 }
Function: 2
Args:
- Callee: 4
- String: 5
- Caller: 2
DebugLoc: { File: 3, Line: 6, Column: 0 }
- String: 6
...
```
And the string table in the .remarks/__remarks section containing:
```
inline\0NoDefinition\0printArgsNoRet\0
test-suite/SingleSource/UnitTests/2002-04-17-PrintfChar.c\0printf\0
will not be inlined into \0 because its definition is unavailable\0
```
This is mostly supposed to be used for testing purposes, but it gives us
a 2x reduction in the remark size, and is an incremental change for the
updates to the remarks file format.
Differential Revision: https://reviews.llvm.org/D60227
llvm-svn: 359050
2019-04-24 08:06:24 +08:00
|
|
|
[&](const ErrorInfoBase &EIB) { EIB.log(Stream); });
|
|
|
|
EXPECT_TRUE(
|
|
|
|
StringRef(Stream.str())
|
|
|
|
.contains("String with index 50 is out of bounds (size = 1)."));
|
|
|
|
}
|