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

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