1 //===-- clang-doc/BitcodeTest.cpp -----------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
20 template <typename T
> static std::string
writeInfo(T
&I
) {
21 SmallString
<2048> Buffer
;
22 llvm::BitstreamWriter
Stream(Buffer
);
23 ClangDocBitcodeWriter
Writer(Stream
);
25 return Buffer
.str().str();
28 std::string
writeInfo(Info
*I
) {
30 case InfoType::IT_namespace
:
31 return writeInfo(*static_cast<NamespaceInfo
*>(I
));
32 case InfoType::IT_record
:
33 return writeInfo(*static_cast<RecordInfo
*>(I
));
34 case InfoType::IT_enum
:
35 return writeInfo(*static_cast<EnumInfo
*>(I
));
36 case InfoType::IT_function
:
37 return writeInfo(*static_cast<FunctionInfo
*>(I
));
38 case InfoType::IT_typedef
:
39 return writeInfo(*static_cast<TypedefInfo
*>(I
));
45 std::vector
<std::unique_ptr
<Info
>> readInfo(StringRef Bitcode
,
47 llvm::BitstreamCursor
Stream(Bitcode
);
48 doc::ClangDocBitcodeReader
Reader(Stream
);
49 auto Infos
= Reader
.readBitcode();
51 // Check that there was no error in the read.
53 EXPECT_EQ(Infos
.get().size(), NumInfos
);
54 return std::move(Infos
.get());
57 TEST(BitcodeTest
, emitNamespaceInfoBitcode
) {
60 I
.Namespace
.emplace_back(EmptySID
, "A", InfoType::IT_namespace
);
62 I
.Children
.Namespaces
.emplace_back(EmptySID
, "ChildNamespace",
63 InfoType::IT_namespace
);
64 I
.Children
.Records
.emplace_back(EmptySID
, "ChildStruct", InfoType::IT_record
);
65 I
.Children
.Functions
.emplace_back();
66 I
.Children
.Enums
.emplace_back();
68 std::string WriteResult
= writeInfo(&I
);
69 EXPECT_TRUE(WriteResult
.size() > 0);
70 std::vector
<std::unique_ptr
<Info
>> ReadResults
= readInfo(WriteResult
, 1);
72 CheckNamespaceInfo(&I
, InfoAsNamespace(ReadResults
[0].get()));
75 TEST(BitcodeTest
, emitRecordInfoBitcode
) {
78 I
.Namespace
.emplace_back(EmptySID
, "A", InfoType::IT_namespace
);
80 I
.DefLoc
= Location(10, llvm::SmallString
<16>{"test.cpp"});
81 I
.Loc
.emplace_back(12, llvm::SmallString
<16>{"test.cpp"});
83 I
.Members
.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private
);
84 I
.TagType
= TagTypeKind::Class
;
86 I
.Bases
.emplace_back(EmptySID
, "F", "path/to/F", true,
87 AccessSpecifier::AS_public
, true);
88 I
.Bases
.back().Children
.Functions
.emplace_back();
89 I
.Bases
.back().Members
.emplace_back(TypeInfo("int"), "X",
90 AccessSpecifier::AS_private
);
91 I
.Parents
.emplace_back(EmptySID
, "F", InfoType::IT_record
);
92 I
.VirtualParents
.emplace_back(EmptySID
, "G", InfoType::IT_record
);
94 // Documentation for the data member.
95 CommentInfo TopComment
;
96 TopComment
.Kind
= "FullComment";
97 TopComment
.Children
.emplace_back(std::make_unique
<CommentInfo
>());
98 CommentInfo
*Brief
= TopComment
.Children
.back().get();
99 Brief
->Kind
= "ParagraphComment";
100 Brief
->Children
.emplace_back(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(std::move(TopComment
));
106 I
.Children
.Records
.emplace_back(EmptySID
, "ChildStruct", InfoType::IT_record
);
107 I
.Children
.Functions
.emplace_back();
108 I
.Children
.Enums
.emplace_back();
110 std::string WriteResult
= writeInfo(&I
);
111 EXPECT_TRUE(WriteResult
.size() > 0);
112 std::vector
<std::unique_ptr
<Info
>> ReadResults
= readInfo(WriteResult
, 1);
114 CheckRecordInfo(&I
, InfoAsRecord(ReadResults
[0].get()));
117 TEST(BitcodeTest
, emitFunctionInfoBitcode
) {
120 I
.Namespace
.emplace_back(EmptySID
, "A", InfoType::IT_namespace
);
122 I
.DefLoc
= Location(10, llvm::SmallString
<16>{"test.cpp"});
123 I
.Loc
.emplace_back(12, llvm::SmallString
<16>{"test.cpp"});
125 I
.ReturnType
= TypeInfo("void");
126 I
.Params
.emplace_back(TypeInfo("int"), "P");
128 I
.Access
= AccessSpecifier::AS_none
;
130 std::string WriteResult
= writeInfo(&I
);
131 EXPECT_TRUE(WriteResult
.size() > 0);
132 std::vector
<std::unique_ptr
<Info
>> ReadResults
= readInfo(WriteResult
, 1);
134 CheckFunctionInfo(&I
, InfoAsFunction(ReadResults
[0].get()));
137 TEST(BitcodeTest
, emitMethodInfoBitcode
) {
140 I
.Namespace
.emplace_back(EmptySID
, "A", InfoType::IT_namespace
);
142 I
.DefLoc
= Location(10, llvm::SmallString
<16>{"test.cpp"});
143 I
.Loc
.emplace_back(12, llvm::SmallString
<16>{"test.cpp"});
145 I
.ReturnType
= TypeInfo("void");
146 I
.Params
.emplace_back(TypeInfo("int"), "P");
148 I
.Parent
= Reference(EmptySID
, "Parent", InfoType::IT_record
);
150 I
.Access
= AccessSpecifier::AS_public
;
152 std::string WriteResult
= writeInfo(&I
);
153 EXPECT_TRUE(WriteResult
.size() > 0);
154 std::vector
<std::unique_ptr
<Info
>> ReadResults
= readInfo(WriteResult
, 1);
156 CheckFunctionInfo(&I
, InfoAsFunction(ReadResults
[0].get()));
159 TEST(BitcodeTest
, emitEnumInfoBitcode
) {
162 I
.Namespace
.emplace_back(EmptySID
, "A", InfoType::IT_namespace
);
164 I
.DefLoc
= Location(10, llvm::SmallString
<16>{"test.cpp"});
165 I
.Loc
.emplace_back(12, llvm::SmallString
<16>{"test.cpp"});
167 I
.Members
.emplace_back("X");
170 std::string WriteResult
= writeInfo(&I
);
171 EXPECT_TRUE(WriteResult
.size() > 0);
172 std::vector
<std::unique_ptr
<Info
>> ReadResults
= readInfo(WriteResult
, 1);
174 CheckEnumInfo(&I
, InfoAsEnum(ReadResults
[0].get()));
177 TEST(BitcodeTest
, emitTypedefInfoBitcode
) {
180 I
.Namespace
.emplace_back(EmptySID
, "A", InfoType::IT_namespace
);
182 I
.DefLoc
= Location(10, llvm::SmallString
<16>{"test.cpp"});
183 I
.Underlying
= TypeInfo("unsigned");
187 Top
.Kind
= "FullComment";
189 Top
.Children
.emplace_back(std::make_unique
<CommentInfo
>());
190 CommentInfo
*BlankLine
= Top
.Children
.back().get();
191 BlankLine
->Kind
= "ParagraphComment";
192 BlankLine
->Children
.emplace_back(std::make_unique
<CommentInfo
>());
193 BlankLine
->Children
.back()->Kind
= "TextComment";
195 I
.Description
.emplace_back(std::move(Top
));
197 std::string WriteResult
= writeInfo(&I
);
198 EXPECT_TRUE(WriteResult
.size() > 0);
199 std::vector
<std::unique_ptr
<Info
>> ReadResults
= readInfo(WriteResult
, 1);
201 CheckTypedefInfo(&I
, InfoAsTypedef(ReadResults
[0].get()));
203 // Check one with no IsUsing set, no description, and no definition location.
205 I2
.Name
= "SomethingElse";
207 I2
.Underlying
= TypeInfo("int");
209 WriteResult
= writeInfo(&I2
);
210 EXPECT_TRUE(WriteResult
.size() > 0);
211 ReadResults
= readInfo(WriteResult
, 1);
212 CheckTypedefInfo(&I2
, InfoAsTypedef(ReadResults
[0].get()));
215 TEST(SerializeTest
, emitInfoWithCommentBitcode
) {
218 F
.ReturnType
= TypeInfo("void");
219 F
.DefLoc
= Location(0, llvm::SmallString
<16>{"test.cpp"});
220 F
.Params
.emplace_back(TypeInfo("int"), "I");
223 Top
.Kind
= "FullComment";
225 Top
.Children
.emplace_back(std::make_unique
<CommentInfo
>());
226 CommentInfo
*BlankLine
= Top
.Children
.back().get();
227 BlankLine
->Kind
= "ParagraphComment";
228 BlankLine
->Children
.emplace_back(std::make_unique
<CommentInfo
>());
229 BlankLine
->Children
.back()->Kind
= "TextComment";
231 Top
.Children
.emplace_back(std::make_unique
<CommentInfo
>());
232 CommentInfo
*Brief
= Top
.Children
.back().get();
233 Brief
->Kind
= "ParagraphComment";
234 Brief
->Children
.emplace_back(std::make_unique
<CommentInfo
>());
235 Brief
->Children
.back()->Kind
= "TextComment";
236 Brief
->Children
.back()->Name
= "ParagraphComment";
237 Brief
->Children
.back()->Text
= " Brief description.";
239 Top
.Children
.emplace_back(std::make_unique
<CommentInfo
>());
240 CommentInfo
*Extended
= Top
.Children
.back().get();
241 Extended
->Kind
= "ParagraphComment";
242 Extended
->Children
.emplace_back(std::make_unique
<CommentInfo
>());
243 Extended
->Children
.back()->Kind
= "TextComment";
244 Extended
->Children
.back()->Text
= " Extended description that";
245 Extended
->Children
.emplace_back(std::make_unique
<CommentInfo
>());
246 Extended
->Children
.back()->Kind
= "TextComment";
247 Extended
->Children
.back()->Text
= " continues onto the next line.";
249 Top
.Children
.emplace_back(std::make_unique
<CommentInfo
>());
250 CommentInfo
*HTML
= Top
.Children
.back().get();
251 HTML
->Kind
= "ParagraphComment";
252 HTML
->Children
.emplace_back(std::make_unique
<CommentInfo
>());
253 HTML
->Children
.back()->Kind
= "TextComment";
254 HTML
->Children
.emplace_back(std::make_unique
<CommentInfo
>());
255 HTML
->Children
.back()->Kind
= "HTMLStartTagComment";
256 HTML
->Children
.back()->Name
= "ul";
257 HTML
->Children
.back()->AttrKeys
.emplace_back("class");
258 HTML
->Children
.back()->AttrValues
.emplace_back("test");
259 HTML
->Children
.emplace_back(std::make_unique
<CommentInfo
>());
260 HTML
->Children
.back()->Kind
= "HTMLStartTagComment";
261 HTML
->Children
.back()->Name
= "li";
262 HTML
->Children
.emplace_back(std::make_unique
<CommentInfo
>());
263 HTML
->Children
.back()->Kind
= "TextComment";
264 HTML
->Children
.back()->Text
= " Testing.";
265 HTML
->Children
.emplace_back(std::make_unique
<CommentInfo
>());
266 HTML
->Children
.back()->Kind
= "HTMLEndTagComment";
267 HTML
->Children
.back()->Name
= "ul";
268 HTML
->Children
.back()->SelfClosing
= true;
270 Top
.Children
.emplace_back(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(std::make_unique
<CommentInfo
>());
276 Verbatim
->Children
.back()->Kind
= "VerbatimBlockLineComment";
277 Verbatim
->Children
.back()->Text
= " The description continues.";
279 Top
.Children
.emplace_back(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(std::make_unique
<CommentInfo
>());
286 ParamOut
->Children
.back()->Kind
= "ParagraphComment";
287 ParamOut
->Children
.back()->Children
.emplace_back(
288 std::make_unique
<CommentInfo
>());
289 ParamOut
->Children
.back()->Children
.back()->Kind
= "TextComment";
290 ParamOut
->Children
.back()->Children
.emplace_back(
291 std::make_unique
<CommentInfo
>());
292 ParamOut
->Children
.back()->Children
.back()->Kind
= "TextComment";
293 ParamOut
->Children
.back()->Children
.back()->Text
= " is a parameter.";
295 Top
.Children
.emplace_back(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(std::make_unique
<CommentInfo
>());
301 ParamIn
->Children
.back()->Kind
= "ParagraphComment";
302 ParamIn
->Children
.back()->Children
.emplace_back(
303 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 std::make_unique
<CommentInfo
>());
308 ParamIn
->Children
.back()->Children
.back()->Kind
= "TextComment";
310 Top
.Children
.emplace_back(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(std::make_unique
<CommentInfo
>());
316 Return
->Children
.back()->Kind
= "ParagraphComment";
317 Return
->Children
.back()->Children
.emplace_back(
318 std::make_unique
<CommentInfo
>());
319 Return
->Children
.back()->Children
.back()->Kind
= "TextComment";
320 Return
->Children
.back()->Children
.back()->Text
= "void";
322 F
.Description
.emplace_back(std::move(Top
));
324 std::string WriteResult
= writeInfo(&F
);
325 EXPECT_TRUE(WriteResult
.size() > 0);
326 std::vector
<std::unique_ptr
<Info
>> ReadResults
= readInfo(WriteResult
, 1);
328 CheckFunctionInfo(&F
, InfoAsFunction(ReadResults
[0].get()));