1//===-- clang-doc/BitcodeTest.cpp -----------------------------------------===//
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 "BitcodeReader.h"
10#include "BitcodeWriter.h"
11#include "ClangDocTest.h"
12#include "Representation.h"
13#include "llvm/Bitstream/BitstreamReader.h"
14#include "llvm/Bitstream/BitstreamWriter.h"
15#include "gtest/gtest.h"
16
17namespace clang {
18namespace doc {
19
20template <typename T> static std::string writeInfo(T &I) {
21 SmallString<2048> Buffer;
22 llvm::BitstreamWriter Stream(Buffer);
23 ClangDocBitcodeWriter Writer(Stream);
24 Writer.emitBlock(I);
25 return Buffer.str().str();
26}
27
28std::string writeInfo(Info *I) {
29 switch (I->IT) {
30 case InfoType::IT_namespace:
31 return writeInfo(I&: *static_cast<NamespaceInfo *>(I));
32 case InfoType::IT_record:
33 return writeInfo(I&: *static_cast<RecordInfo *>(I));
34 case InfoType::IT_enum:
35 return writeInfo(I&: *static_cast<EnumInfo *>(I));
36 case InfoType::IT_function:
37 return writeInfo(I&: *static_cast<FunctionInfo *>(I));
38 case InfoType::IT_typedef:
39 return writeInfo(I&: *static_cast<TypedefInfo *>(I));
40 default:
41 return "";
42 }
43}
44
45std::vector<std::unique_ptr<Info>> readInfo(StringRef Bitcode,
46 size_t NumInfos) {
47 llvm::BitstreamCursor Stream(Bitcode);
48 doc::ClangDocBitcodeReader Reader(Stream);
49 auto Infos = Reader.readBitcode();
50
51 // Check that there was no error in the read.
52 assert(Infos);
53 EXPECT_EQ(Infos.get().size(), NumInfos);
54 return std::move(Infos.get());
55}
56
57TEST(BitcodeTest, emitNamespaceInfoBitcode) {
58 NamespaceInfo I;
59 I.Name = "r";
60 I.Namespace.emplace_back(Args: EmptySID, Args: "A", Args: InfoType::IT_namespace);
61
62 I.Children.Namespaces.emplace_back(args: EmptySID, args: "ChildNamespace",
63 args: InfoType::IT_namespace);
64 I.Children.Records.emplace_back(args: EmptySID, args: "ChildStruct", args: InfoType::IT_record);
65 I.Children.Functions.emplace_back();
66 I.Children.Enums.emplace_back();
67
68 std::string WriteResult = writeInfo(I: &I);
69 EXPECT_TRUE(WriteResult.size() > 0);
70 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(Bitcode: WriteResult, NumInfos: 1);
71
72 CheckNamespaceInfo(Expected: &I, Actual: InfoAsNamespace(I: ReadResults[0].get()));
73}
74
75TEST(BitcodeTest, emitRecordInfoBitcode) {
76 RecordInfo I;
77 I.Name = "r";
78 I.Namespace.emplace_back(Args: EmptySID, Args: "A", Args: InfoType::IT_namespace);
79
80 I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
81 I.Loc.emplace_back(Args: 12, Args: llvm::SmallString<16>{"test.cpp"});
82
83 I.Members.emplace_back(Args: TypeInfo("int"), Args: "X", Args: AccessSpecifier::AS_private);
84 I.TagType = TagTypeKind::Class;
85 I.IsTypeDef = true;
86 I.Bases.emplace_back(args: EmptySID, args: "F", args: "path/to/F", args: true,
87 args: AccessSpecifier::AS_public, args: true);
88 I.Bases.back().Children.Functions.emplace_back();
89 I.Bases.back().Members.emplace_back(Args: TypeInfo("int"), Args: "X",
90 Args: AccessSpecifier::AS_private);
91 I.Parents.emplace_back(Args: EmptySID, Args: "F", Args: InfoType::IT_record);
92 I.VirtualParents.emplace_back(Args: EmptySID, Args: "G", Args: InfoType::IT_record);
93
94 // Documentation for the data member.
95 CommentInfo TopComment;
96 TopComment.Kind = "FullComment";
97 TopComment.Children.emplace_back(args: std::make_unique<CommentInfo>());
98 CommentInfo *Brief = TopComment.Children.back().get();
99 Brief->Kind = "ParagraphComment";
100 Brief->Children.emplace_back(args: std::make_unique<CommentInfo>());
101 Brief->Children.back()->Kind = "TextComment";
102 Brief->Children.back()->Name = "ParagraphComment";
103 Brief->Children.back()->Text = "Value of the thing.";
104 I.Bases.back().Members.back().Description.emplace_back(args: std::move(TopComment));
105
106 I.Children.Records.emplace_back(args: EmptySID, args: "ChildStruct", args: InfoType::IT_record);
107 I.Children.Functions.emplace_back();
108 I.Children.Enums.emplace_back();
109
110 std::string WriteResult = writeInfo(I: &I);
111 EXPECT_TRUE(WriteResult.size() > 0);
112 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(Bitcode: WriteResult, NumInfos: 1);
113
114 CheckRecordInfo(Expected: &I, Actual: InfoAsRecord(I: ReadResults[0].get()));
115}
116
117TEST(BitcodeTest, emitFunctionInfoBitcode) {
118 FunctionInfo I;
119 I.Name = "f";
120 I.Namespace.emplace_back(Args: EmptySID, Args: "A", Args: InfoType::IT_namespace);
121
122 I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
123 I.Loc.emplace_back(Args: 12, Args: llvm::SmallString<16>{"test.cpp"});
124
125 I.ReturnType = TypeInfo("void");
126 I.Params.emplace_back(Args: TypeInfo("int"), Args: "P");
127
128 I.Access = AccessSpecifier::AS_none;
129
130 std::string WriteResult = writeInfo(I: &I);
131 EXPECT_TRUE(WriteResult.size() > 0);
132 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(Bitcode: WriteResult, NumInfos: 1);
133
134 CheckFunctionInfo(Expected: &I, Actual: InfoAsFunction(I: ReadResults[0].get()));
135}
136
137TEST(BitcodeTest, emitMethodInfoBitcode) {
138 FunctionInfo I;
139 I.Name = "f";
140 I.Namespace.emplace_back(Args: EmptySID, Args: "A", Args: InfoType::IT_namespace);
141
142 I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
143 I.Loc.emplace_back(Args: 12, Args: llvm::SmallString<16>{"test.cpp"});
144
145 I.ReturnType = TypeInfo("void");
146 I.Params.emplace_back(Args: TypeInfo("int"), Args: "P");
147 I.IsMethod = true;
148 I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
149
150 I.Access = AccessSpecifier::AS_public;
151
152 std::string WriteResult = writeInfo(I: &I);
153 EXPECT_TRUE(WriteResult.size() > 0);
154 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(Bitcode: WriteResult, NumInfos: 1);
155
156 CheckFunctionInfo(Expected: &I, Actual: InfoAsFunction(I: ReadResults[0].get()));
157}
158
159TEST(BitcodeTest, emitEnumInfoBitcode) {
160 EnumInfo I;
161 I.Name = "e";
162 I.Namespace.emplace_back(Args: EmptySID, Args: "A", Args: InfoType::IT_namespace);
163
164 I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
165 I.Loc.emplace_back(Args: 12, Args: llvm::SmallString<16>{"test.cpp"});
166
167 I.Members.emplace_back(Args: "X");
168 I.Scoped = true;
169
170 std::string WriteResult = writeInfo(I: &I);
171 EXPECT_TRUE(WriteResult.size() > 0);
172 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(Bitcode: WriteResult, NumInfos: 1);
173
174 CheckEnumInfo(Expected: &I, Actual: InfoAsEnum(I: ReadResults[0].get()));
175}
176
177TEST(BitcodeTest, emitTypedefInfoBitcode) {
178 TypedefInfo I;
179 I.Name = "MyInt";
180 I.Namespace.emplace_back(Args: EmptySID, Args: "A", Args: InfoType::IT_namespace);
181
182 I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
183 I.Underlying = TypeInfo("unsigned");
184 I.IsUsing = true;
185
186 CommentInfo Top;
187 Top.Kind = "FullComment";
188
189 Top.Children.emplace_back(args: std::make_unique<CommentInfo>());
190 CommentInfo *BlankLine = Top.Children.back().get();
191 BlankLine->Kind = "ParagraphComment";
192 BlankLine->Children.emplace_back(args: std::make_unique<CommentInfo>());
193 BlankLine->Children.back()->Kind = "TextComment";
194
195 I.Description.emplace_back(args: std::move(Top));
196
197 std::string WriteResult = writeInfo(I: &I);
198 EXPECT_TRUE(WriteResult.size() > 0);
199 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(Bitcode: WriteResult, NumInfos: 1);
200
201 CheckTypedefInfo(Expected: &I, Actual: InfoAsTypedef(I: ReadResults[0].get()));
202
203 // Check one with no IsUsing set, no description, and no definition location.
204 TypedefInfo I2;
205 I2.Name = "SomethingElse";
206 I2.IsUsing = false;
207 I2.Underlying = TypeInfo("int");
208
209 WriteResult = writeInfo(I: &I2);
210 EXPECT_TRUE(WriteResult.size() > 0);
211 ReadResults = readInfo(Bitcode: WriteResult, NumInfos: 1);
212 CheckTypedefInfo(Expected: &I2, Actual: InfoAsTypedef(I: ReadResults[0].get()));
213}
214
215TEST(SerializeTest, emitInfoWithCommentBitcode) {
216 FunctionInfo F;
217 F.Name = "F";
218 F.ReturnType = TypeInfo("void");
219 F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
220 F.Params.emplace_back(Args: TypeInfo("int"), Args: "I");
221
222 CommentInfo Top;
223 Top.Kind = "FullComment";
224
225 Top.Children.emplace_back(args: std::make_unique<CommentInfo>());
226 CommentInfo *BlankLine = Top.Children.back().get();
227 BlankLine->Kind = "ParagraphComment";
228 BlankLine->Children.emplace_back(args: std::make_unique<CommentInfo>());
229 BlankLine->Children.back()->Kind = "TextComment";
230
231 Top.Children.emplace_back(args: std::make_unique<CommentInfo>());
232 CommentInfo *Brief = Top.Children.back().get();
233 Brief->Kind = "ParagraphComment";
234 Brief->Children.emplace_back(args: std::make_unique<CommentInfo>());
235 Brief->Children.back()->Kind = "TextComment";
236 Brief->Children.back()->Name = "ParagraphComment";
237 Brief->Children.back()->Text = " Brief description.";
238
239 Top.Children.emplace_back(args: std::make_unique<CommentInfo>());
240 CommentInfo *Extended = Top.Children.back().get();
241 Extended->Kind = "ParagraphComment";
242 Extended->Children.emplace_back(args: std::make_unique<CommentInfo>());
243 Extended->Children.back()->Kind = "TextComment";
244 Extended->Children.back()->Text = " Extended description that";
245 Extended->Children.emplace_back(args: std::make_unique<CommentInfo>());
246 Extended->Children.back()->Kind = "TextComment";
247 Extended->Children.back()->Text = " continues onto the next line.";
248
249 Top.Children.emplace_back(args: std::make_unique<CommentInfo>());
250 CommentInfo *HTML = Top.Children.back().get();
251 HTML->Kind = "ParagraphComment";
252 HTML->Children.emplace_back(args: std::make_unique<CommentInfo>());
253 HTML->Children.back()->Kind = "TextComment";
254 HTML->Children.emplace_back(args: std::make_unique<CommentInfo>());
255 HTML->Children.back()->Kind = "HTMLStartTagComment";
256 HTML->Children.back()->Name = "ul";
257 HTML->Children.back()->AttrKeys.emplace_back(Args: "class");
258 HTML->Children.back()->AttrValues.emplace_back(Args: "test");
259 HTML->Children.emplace_back(args: std::make_unique<CommentInfo>());
260 HTML->Children.back()->Kind = "HTMLStartTagComment";
261 HTML->Children.back()->Name = "li";
262 HTML->Children.emplace_back(args: std::make_unique<CommentInfo>());
263 HTML->Children.back()->Kind = "TextComment";
264 HTML->Children.back()->Text = " Testing.";
265 HTML->Children.emplace_back(args: std::make_unique<CommentInfo>());
266 HTML->Children.back()->Kind = "HTMLEndTagComment";
267 HTML->Children.back()->Name = "ul";
268 HTML->Children.back()->SelfClosing = true;
269
270 Top.Children.emplace_back(args: std::make_unique<CommentInfo>());
271 CommentInfo *Verbatim = Top.Children.back().get();
272 Verbatim->Kind = "VerbatimBlockComment";
273 Verbatim->Name = "verbatim";
274 Verbatim->CloseName = "endverbatim";
275 Verbatim->Children.emplace_back(args: std::make_unique<CommentInfo>());
276 Verbatim->Children.back()->Kind = "VerbatimBlockLineComment";
277 Verbatim->Children.back()->Text = " The description continues.";
278
279 Top.Children.emplace_back(args: std::make_unique<CommentInfo>());
280 CommentInfo *ParamOut = Top.Children.back().get();
281 ParamOut->Kind = "ParamCommandComment";
282 ParamOut->Direction = "[out]";
283 ParamOut->ParamName = "I";
284 ParamOut->Explicit = true;
285 ParamOut->Children.emplace_back(args: std::make_unique<CommentInfo>());
286 ParamOut->Children.back()->Kind = "ParagraphComment";
287 ParamOut->Children.back()->Children.emplace_back(
288 args: std::make_unique<CommentInfo>());
289 ParamOut->Children.back()->Children.back()->Kind = "TextComment";
290 ParamOut->Children.back()->Children.emplace_back(
291 args: std::make_unique<CommentInfo>());
292 ParamOut->Children.back()->Children.back()->Kind = "TextComment";
293 ParamOut->Children.back()->Children.back()->Text = " is a parameter.";
294
295 Top.Children.emplace_back(args: std::make_unique<CommentInfo>());
296 CommentInfo *ParamIn = Top.Children.back().get();
297 ParamIn->Kind = "ParamCommandComment";
298 ParamIn->Direction = "[in]";
299 ParamIn->ParamName = "J";
300 ParamIn->Children.emplace_back(args: std::make_unique<CommentInfo>());
301 ParamIn->Children.back()->Kind = "ParagraphComment";
302 ParamIn->Children.back()->Children.emplace_back(
303 args: std::make_unique<CommentInfo>());
304 ParamIn->Children.back()->Children.back()->Kind = "TextComment";
305 ParamIn->Children.back()->Children.back()->Text = " is a parameter.";
306 ParamIn->Children.back()->Children.emplace_back(
307 args: std::make_unique<CommentInfo>());
308 ParamIn->Children.back()->Children.back()->Kind = "TextComment";
309
310 Top.Children.emplace_back(args: std::make_unique<CommentInfo>());
311 CommentInfo *Return = Top.Children.back().get();
312 Return->Kind = "BlockCommandComment";
313 Return->Name = "return";
314 Return->Explicit = true;
315 Return->Children.emplace_back(args: std::make_unique<CommentInfo>());
316 Return->Children.back()->Kind = "ParagraphComment";
317 Return->Children.back()->Children.emplace_back(
318 args: std::make_unique<CommentInfo>());
319 Return->Children.back()->Children.back()->Kind = "TextComment";
320 Return->Children.back()->Children.back()->Text = "void";
321
322 F.Description.emplace_back(args: std::move(Top));
323
324 std::string WriteResult = writeInfo(I: &F);
325 EXPECT_TRUE(WriteResult.size() > 0);
326 std::vector<std::unique_ptr<Info>> ReadResults = readInfo(Bitcode: WriteResult, NumInfos: 1);
327
328 CheckFunctionInfo(Expected: &F, Actual: InfoAsFunction(I: ReadResults[0].get()));
329}
330
331} // namespace doc
332} // namespace clang
333

source code of clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp