1//===- unittest/Support/RemarksLinkingTest.cpp - Linking 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/Bitcode/BitcodeAnalyzer.h"
10#include "llvm/Remarks/RemarkLinker.h"
11#include "llvm/Remarks/RemarkSerializer.h"
12#include "llvm/Support/raw_ostream.h"
13#include "gtest/gtest.h"
14#include <string>
15
16using namespace llvm;
17
18static void serializeAndCheck(remarks::RemarkLinker &RL,
19 remarks::Format OutputFormat,
20 StringRef ExpectedOutput) {
21 // 1. Create a serializer.
22 // 2. Serialize all the remarks from the linker.
23 // 3. Check that it matches the output.
24 std::string Buf;
25 raw_string_ostream OS(Buf);
26 Error E = RL.serialize(OS, RemarksFormat: OutputFormat);
27 EXPECT_FALSE(static_cast<bool>(E));
28
29 // For bitstream, run it through the analyzer.
30 if (OutputFormat == remarks::Format::Bitstream) {
31 std::string AnalyzeBuf;
32 raw_string_ostream AnalyzeOS(AnalyzeBuf);
33 BCDumpOptions O(AnalyzeOS);
34 O.ShowBinaryBlobs = true;
35 BitcodeAnalyzer BA(OS.str());
36 EXPECT_FALSE(BA.analyze(O)); // Expect no errors.
37 EXPECT_EQ(AnalyzeOS.str(), ExpectedOutput);
38 } else {
39 EXPECT_EQ(OS.str(), ExpectedOutput);
40 }
41}
42
43static void check(remarks::Format InputFormat, StringRef Input,
44 remarks::Format OutputFormat, StringRef ExpectedOutput,
45 std::optional<bool> KeepAllRemarks = {}) {
46 remarks::RemarkLinker RL;
47 if (KeepAllRemarks)
48 RL.setKeepAllRemarks(*KeepAllRemarks);
49 EXPECT_FALSE(RL.link(Input, InputFormat));
50 serializeAndCheck(RL, OutputFormat, ExpectedOutput);
51}
52
53static void check(remarks::Format InputFormat, StringRef Input,
54 remarks::Format InputFormat2, StringRef Input2,
55 remarks::Format OutputFormat, StringRef ExpectedOutput) {
56 remarks::RemarkLinker RL;
57 EXPECT_FALSE(RL.link(Input, InputFormat));
58 EXPECT_FALSE(RL.link(Input2, InputFormat2));
59 serializeAndCheck(RL, OutputFormat, ExpectedOutput);
60}
61
62TEST(Remarks, LinkingGoodYAML) {
63 // One YAML remark.
64 check(InputFormat: remarks::Format::YAML,
65 Input: "--- !Missed\n"
66 "Pass: inline\n"
67 "Name: NoDefinition\n"
68 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
69 "Function: foo\n"
70 "...\n",
71 OutputFormat: remarks::Format::YAML,
72 ExpectedOutput: "--- !Missed\n"
73 "Pass: inline\n"
74 "Name: NoDefinition\n"
75 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
76 "Function: foo\n"
77 "...\n");
78
79 // Check that we don't keep remarks without debug locations, unless
80 // KeepAllRemarks is set.
81 check(InputFormat: remarks::Format::YAML,
82 Input: "--- !Missed\n"
83 "Pass: inline\n"
84 "Name: NoDefinition\n"
85 "Function: foo\n"
86 "...\n",
87 OutputFormat: remarks::Format::YAML, ExpectedOutput: "",
88 /*KeepAllRemarks=*/false);
89 check(InputFormat: remarks::Format::YAML,
90 Input: "--- !Missed\n"
91 "Pass: inline\n"
92 "Name: NoDefinition\n"
93 "Function: foo\n"
94 "...\n",
95 OutputFormat: remarks::Format::YAML,
96 ExpectedOutput: "--- !Missed\n"
97 "Pass: inline\n"
98 "Name: NoDefinition\n"
99 "Function: foo\n"
100 "...\n");
101
102 // Check that we deduplicate remarks.
103 check(InputFormat: remarks::Format::YAML,
104 Input: "--- !Missed\n"
105 "Pass: inline\n"
106 "Name: NoDefinition\n"
107 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
108 "Function: foo\n"
109 "...\n"
110 "--- !Missed\n"
111 "Pass: inline\n"
112 "Name: NoDefinition\n"
113 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
114 "Function: foo\n"
115 "...\n",
116 OutputFormat: remarks::Format::YAML,
117 ExpectedOutput: "--- !Missed\n"
118 "Pass: inline\n"
119 "Name: NoDefinition\n"
120 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
121 "Function: foo\n"
122 "...\n");
123}
124
125TEST(Remarks, LinkingGoodBitstream) {
126 // One YAML remark.
127 check(InputFormat: remarks::Format::YAML,
128 Input: "--- !Missed\n"
129 "Pass: inline\n"
130 "Name: NoDefinition\n"
131 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
132 "Function: foo\n"
133 "...\n",
134 OutputFormat: remarks::Format::Bitstream,
135 ExpectedOutput: "<BLOCKINFO_BLOCK/>\n"
136 "<Meta BlockID=8 NumWords=12 BlockCodeSize=3>\n"
137 " <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
138 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
139 " <String table codeid=3 abbrevid=6/> blob data = "
140 "'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
141 "</Meta>\n"
142 "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
143 " <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
144 " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
145 "</Remark>\n");
146
147 // Check that we keep remarks without debug info.
148 check(InputFormat: remarks::Format::YAML,
149 Input: "--- !Missed\n"
150 "Pass: inline\n"
151 "Name: NoDefinition\n"
152 "Function: foo\n"
153 "...\n",
154 OutputFormat: remarks::Format::Bitstream,
155 ExpectedOutput: "<BLOCKINFO_BLOCK/>\n"
156 "<Meta BlockID=8 NumWords=10 BlockCodeSize=3>\n"
157 " <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
158 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
159 " <String table codeid=3 abbrevid=6/> blob data = "
160 "'inline\\x00NoDefinition\\x00foo\\x00'\n"
161 "</Meta>\n"
162 "<Remark BlockID=9 NumWords=1 BlockCodeSize=4>\n"
163 " <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
164 "</Remark>\n");
165
166 // Check that we deduplicate remarks.
167 check(InputFormat: remarks::Format::YAML,
168 Input: "--- !Missed\n"
169 "Pass: inline\n"
170 "Name: NoDefinition\n"
171 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
172 "Function: foo\n"
173 "...\n"
174 "--- !Missed\n"
175 "Pass: inline\n"
176 "Name: NoDefinition\n"
177 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
178 "Function: foo\n"
179 "...\n",
180 OutputFormat: remarks::Format::Bitstream,
181 ExpectedOutput: "<BLOCKINFO_BLOCK/>\n"
182 "<Meta BlockID=8 NumWords=12 BlockCodeSize=3>\n"
183 " <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
184 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"
185 " <String table codeid=3 abbrevid=6/> blob data = "
186 "'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
187 "</Meta>\n"
188 "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
189 " <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
190 " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
191 "</Remark>\n");
192}
193
194TEST(Remarks, LinkingGoodStrTab) {
195 // Check that remarks from different entries use the same strtab.
196 check(InputFormat: remarks::Format::YAML,
197 Input: "--- !Missed\n"
198 "Pass: inline\n"
199 "Name: NoDefinition\n"
200 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
201 "Function: foo\n"
202 "...\n",
203 InputFormat2: remarks::Format::YAML,
204 Input2: "--- !Passed\n"
205 "Pass: inline\n"
206 "Name: Ok\n"
207 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
208 "Function: foo\n"
209 "...\n",
210 OutputFormat: remarks::Format::YAMLStrTab,
211 ExpectedOutput: StringRef("REMARKS\0\0\0\0\0\0\0\0\0\x22\0\0\0\0\0\0\0"
212 "inline\0NoDefinition\0foo\0file.c\0Ok\0"
213 "--- !Passed\n"
214 "Pass: 0\n"
215 "Name: 4\n"
216 "DebugLoc: { File: 3, Line: 3, Column: 12 }\n"
217 "Function: 2\n"
218 "...\n"
219 "--- !Missed\n"
220 "Pass: 0\n"
221 "Name: 1\n"
222 "DebugLoc: { File: 3, Line: 3, Column: 12 }\n"
223 "Function: 2\n"
224 "...\n",
225 304));
226}
227
228// Check that we propagate parsing errors.
229TEST(Remarks, LinkingError) {
230 remarks::RemarkLinker RL;
231 {
232 Error E = RL.link(Buffer: "badyaml", RemarkFormat: remarks::Format::YAML);
233 EXPECT_TRUE(static_cast<bool>(E));
234 EXPECT_EQ(toString(std::move(E)),
235 "YAML:1:1: error: document root is not of mapping type.\n"
236 "\n"
237 "badyaml\n"
238 "^~~~~~~\n"
239 "\n");
240 }
241
242 {
243 // Check that the prepend path is propagated and fails with the full path.
244 RL.setExternalFilePrependPath("/baddir/");
245 Error E = RL.link(
246 Buffer: StringRef("REMARKS\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0badfile.opt.yaml",
247 40),
248 RemarkFormat: remarks::Format::YAMLStrTab);
249 EXPECT_TRUE(static_cast<bool>(E));
250 std::string ErrorMessage = toString(E: std::move(E));
251 EXPECT_EQ(StringRef(ErrorMessage).lower(),
252 StringRef("'/baddir/badfile.opt.yaml': No such file or directory")
253 .lower());
254 }
255}
256

source code of llvm/unittests/Remarks/RemarksLinkingTest.cpp