220 lines
7.9 KiB
C++
220 lines
7.9 KiB
C++
|
//===- unittest/Support/RemarksLinkingTest.cpp - Linking 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/Bitcode/BitcodeAnalyzer.h"
|
||
|
#include "llvm/Remarks/RemarkLinker.h"
|
||
|
#include "llvm/Remarks/RemarkSerializer.h"
|
||
|
#include "llvm/Support/raw_ostream.h"
|
||
|
#include "gtest/gtest.h"
|
||
|
#include <string>
|
||
|
|
||
|
using namespace llvm;
|
||
|
|
||
|
static void serializeAndCheck(remarks::RemarkLinker &RL,
|
||
|
remarks::Format OutputFormat,
|
||
|
StringRef ExpectedOutput) {
|
||
|
// 1. Create a serializer.
|
||
|
// 2. Serialize all the remarks from the linker.
|
||
|
// 3. Check that it matches the output.
|
||
|
std::string Buf;
|
||
|
raw_string_ostream OS(Buf);
|
||
|
Error E = RL.serialize(OS, OutputFormat);
|
||
|
EXPECT_FALSE(static_cast<bool>(E));
|
||
|
|
||
|
// For bitstream, run it through the analyzer.
|
||
|
if (OutputFormat == remarks::Format::Bitstream) {
|
||
|
std::string AnalyzeBuf;
|
||
|
raw_string_ostream AnalyzeOS(AnalyzeBuf);
|
||
|
BCDumpOptions O(AnalyzeOS);
|
||
|
O.ShowBinaryBlobs = true;
|
||
|
BitcodeAnalyzer BA(OS.str());
|
||
|
EXPECT_FALSE(BA.analyze(O)); // Expect no errors.
|
||
|
EXPECT_EQ(AnalyzeOS.str(), ExpectedOutput);
|
||
|
} else {
|
||
|
EXPECT_EQ(OS.str(), ExpectedOutput);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void check(remarks::Format InputFormat, StringRef Input,
|
||
|
remarks::Format OutputFormat, StringRef ExpectedOutput) {
|
||
|
remarks::RemarkLinker RL;
|
||
|
EXPECT_FALSE(RL.link(Input, InputFormat));
|
||
|
serializeAndCheck(RL, OutputFormat, ExpectedOutput);
|
||
|
}
|
||
|
|
||
|
static void check(remarks::Format InputFormat, StringRef Input,
|
||
|
remarks::Format InputFormat2, StringRef Input2,
|
||
|
remarks::Format OutputFormat, StringRef ExpectedOutput) {
|
||
|
remarks::RemarkLinker RL;
|
||
|
EXPECT_FALSE(RL.link(Input, InputFormat));
|
||
|
EXPECT_FALSE(RL.link(Input2, InputFormat2));
|
||
|
serializeAndCheck(RL, OutputFormat, ExpectedOutput);
|
||
|
}
|
||
|
|
||
|
TEST(Remarks, LinkingGoodYAML) {
|
||
|
// One YAML remark.
|
||
|
check(remarks::Format::YAML,
|
||
|
"--- !Missed\n"
|
||
|
"Pass: inline\n"
|
||
|
"Name: NoDefinition\n"
|
||
|
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
|
||
|
"Function: foo\n"
|
||
|
"...\n",
|
||
|
remarks::Format::YAML,
|
||
|
"--- !Missed\n"
|
||
|
"Pass: inline\n"
|
||
|
"Name: NoDefinition\n"
|
||
|
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
|
||
|
"Function: foo\n"
|
||
|
"...\n");
|
||
|
|
||
|
// Check that we don't keep remarks without debug locations.
|
||
|
check(remarks::Format::YAML,
|
||
|
"--- !Missed\n"
|
||
|
"Pass: inline\n"
|
||
|
"Name: NoDefinition\n"
|
||
|
"Function: foo\n"
|
||
|
"...\n",
|
||
|
remarks::Format::YAML, "");
|
||
|
|
||
|
// Check that we deduplicate remarks.
|
||
|
check(remarks::Format::YAML,
|
||
|
"--- !Missed\n"
|
||
|
"Pass: inline\n"
|
||
|
"Name: NoDefinition\n"
|
||
|
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
|
||
|
"Function: foo\n"
|
||
|
"...\n"
|
||
|
"--- !Missed\n"
|
||
|
"Pass: inline\n"
|
||
|
"Name: NoDefinition\n"
|
||
|
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
|
||
|
"Function: foo\n"
|
||
|
"...\n",
|
||
|
remarks::Format::YAML,
|
||
|
"--- !Missed\n"
|
||
|
"Pass: inline\n"
|
||
|
"Name: NoDefinition\n"
|
||
|
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
|
||
|
"Function: foo\n"
|
||
|
"...\n");
|
||
|
}
|
||
|
|
||
|
TEST(Remarks, LinkingGoodBitstream) {
|
||
|
// One YAML remark.
|
||
|
check(remarks::Format::YAML,
|
||
|
"--- !Missed\n"
|
||
|
"Pass: inline\n"
|
||
|
"Name: NoDefinition\n"
|
||
|
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
|
||
|
"Function: foo\n"
|
||
|
"...\n",
|
||
|
remarks::Format::Bitstream,
|
||
|
"<BLOCKINFO_BLOCK/>\n"
|
||
|
"<Meta BlockID=8 NumWords=12 BlockCodeSize=3>\n"
|
||
|
" <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
|
||
|
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
|
||
|
" <String table codeid=3 abbrevid=6/> blob data = "
|
||
|
"'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
|
||
|
"</Meta>\n"
|
||
|
"<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
|
||
|
" <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
|
||
|
" <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
|
||
|
"</Remark>\n");
|
||
|
|
||
|
// Check that we deduplicate remarks.
|
||
|
check(remarks::Format::YAML,
|
||
|
"--- !Missed\n"
|
||
|
"Pass: inline\n"
|
||
|
"Name: NoDefinition\n"
|
||
|
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
|
||
|
"Function: foo\n"
|
||
|
"...\n"
|
||
|
"--- !Missed\n"
|
||
|
"Pass: inline\n"
|
||
|
"Name: NoDefinition\n"
|
||
|
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
|
||
|
"Function: foo\n"
|
||
|
"...\n",
|
||
|
remarks::Format::Bitstream,
|
||
|
"<BLOCKINFO_BLOCK/>\n"
|
||
|
"<Meta BlockID=8 NumWords=12 BlockCodeSize=3>\n"
|
||
|
" <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
|
||
|
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
|
||
|
" <String table codeid=3 abbrevid=6/> blob data = "
|
||
|
"'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
|
||
|
"</Meta>\n"
|
||
|
"<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
|
||
|
" <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
|
||
|
" <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
|
||
|
"</Remark>\n");
|
||
|
}
|
||
|
|
||
|
TEST(Remarks, LinkingGoodStrTab) {
|
||
|
// Check that remarks from different entries use the same strtab.
|
||
|
check(remarks::Format::YAML,
|
||
|
"--- !Missed\n"
|
||
|
"Pass: inline\n"
|
||
|
"Name: NoDefinition\n"
|
||
|
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
|
||
|
"Function: foo\n"
|
||
|
"...\n",
|
||
|
remarks::Format::YAML,
|
||
|
"--- !Passed\n"
|
||
|
"Pass: inline\n"
|
||
|
"Name: Ok\n"
|
||
|
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
|
||
|
"Function: foo\n"
|
||
|
"...\n",
|
||
|
remarks::Format::YAMLStrTab,
|
||
|
StringRef("REMARKS\0\0\0\0\0\0\0\0\0\x22\0\0\0\0\0\0\0"
|
||
|
"inline\0NoDefinition\0foo\0file.c\0Ok\0"
|
||
|
"--- !Passed\n"
|
||
|
"Pass: 0\n"
|
||
|
"Name: 4\n"
|
||
|
"DebugLoc: { File: 3, Line: 3, Column: 12 }\n"
|
||
|
"Function: 2\n"
|
||
|
"...\n"
|
||
|
"--- !Missed\n"
|
||
|
"Pass: 0\n"
|
||
|
"Name: 1\n"
|
||
|
"DebugLoc: { File: 3, Line: 3, Column: 12 }\n"
|
||
|
"Function: 2\n"
|
||
|
"...\n",
|
||
|
304));
|
||
|
}
|
||
|
|
||
|
// Check that we propagate parsing errors.
|
||
|
TEST(Remarks, LinkingError) {
|
||
|
remarks::RemarkLinker RL;
|
||
|
{
|
||
|
Error E = RL.link("badyaml", remarks::Format::YAML);
|
||
|
EXPECT_TRUE(static_cast<bool>(E));
|
||
|
EXPECT_EQ(toString(std::move(E)),
|
||
|
"YAML:1:1: error: document root is not of mapping type.\n"
|
||
|
"\n"
|
||
|
"badyaml\n"
|
||
|
"^~~~~~~\n"
|
||
|
"\n");
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// Check that the prepend path is propagated and fails with the full path.
|
||
|
RL.setExternalFilePrependPath("/baddir/");
|
||
|
Error E = RL.link(
|
||
|
StringRef("REMARKS\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0badfile.opt.yaml",
|
||
|
40),
|
||
|
remarks::Format::YAMLStrTab);
|
||
|
EXPECT_TRUE(static_cast<bool>(E));
|
||
|
std::string ErrorMessage = toString(std::move(E));
|
||
|
EXPECT_EQ(StringRef(ErrorMessage).lower(),
|
||
|
StringRef("'/baddir/badfile.opt.yaml': No such file or directory")
|
||
|
.lower());
|
||
|
}
|
||
|
}
|