xref: /llvm-project/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp (revision edd690b02e16e991393bf7f67631196942369aed)
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 
17 namespace clang {
18 namespace doc {
19 
writeInfo(T & I)20 template <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 
writeInfo(Info * I)28 std::string writeInfo(Info *I) {
29   switch (I->IT) {
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));
40   default:
41     return "";
42   }
43 }
44 
readInfo(StringRef Bitcode,size_t NumInfos)45 std::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 
TEST(BitcodeTest,emitNamespaceInfoBitcode)57 TEST(BitcodeTest, emitNamespaceInfoBitcode) {
58   NamespaceInfo I;
59   I.Name = "r";
60   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
61 
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();
67 
68   std::string WriteResult = writeInfo(&I);
69   EXPECT_TRUE(WriteResult.size() > 0);
70   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
71 
72   CheckNamespaceInfo(&I, InfoAsNamespace(ReadResults[0].get()));
73 }
74 
TEST(BitcodeTest,emitRecordInfoBitcode)75 TEST(BitcodeTest, emitRecordInfoBitcode) {
76   RecordInfo I;
77   I.Name = "r";
78   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
79 
80   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
81   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
82 
83   I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);
84   I.TagType = TagTypeKind::Class;
85   I.IsTypeDef = true;
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);
93 
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));
105 
106   I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
107   I.Children.Functions.emplace_back();
108   I.Children.Enums.emplace_back();
109 
110   std::string WriteResult = writeInfo(&I);
111   EXPECT_TRUE(WriteResult.size() > 0);
112   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
113 
114   CheckRecordInfo(&I, InfoAsRecord(ReadResults[0].get()));
115 }
116 
TEST(BitcodeTest,emitFunctionInfoBitcode)117 TEST(BitcodeTest, emitFunctionInfoBitcode) {
118   FunctionInfo I;
119   I.Name = "f";
120   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
121 
122   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
123   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
124 
125   I.ReturnType = TypeInfo("void");
126   I.Params.emplace_back(TypeInfo("int"), "P");
127 
128   I.Access = AccessSpecifier::AS_none;
129 
130   std::string WriteResult = writeInfo(&I);
131   EXPECT_TRUE(WriteResult.size() > 0);
132   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
133 
134   CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get()));
135 }
136 
TEST(BitcodeTest,emitMethodInfoBitcode)137 TEST(BitcodeTest, emitMethodInfoBitcode) {
138   FunctionInfo I;
139   I.Name = "f";
140   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
141 
142   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
143   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
144 
145   I.ReturnType = TypeInfo("void");
146   I.Params.emplace_back(TypeInfo("int"), "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);
153   EXPECT_TRUE(WriteResult.size() > 0);
154   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
155 
156   CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get()));
157 }
158 
TEST(BitcodeTest,emitEnumInfoBitcode)159 TEST(BitcodeTest, emitEnumInfoBitcode) {
160   EnumInfo I;
161   I.Name = "e";
162   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
163 
164   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
165   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
166 
167   I.Members.emplace_back("X");
168   I.Scoped = true;
169 
170   std::string WriteResult = writeInfo(&I);
171   EXPECT_TRUE(WriteResult.size() > 0);
172   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
173 
174   CheckEnumInfo(&I, InfoAsEnum(ReadResults[0].get()));
175 }
176 
TEST(BitcodeTest,emitTypedefInfoBitcode)177 TEST(BitcodeTest, emitTypedefInfoBitcode) {
178   TypedefInfo I;
179   I.Name = "MyInt";
180   I.Namespace.emplace_back(EmptySID, "A", 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(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";
194 
195   I.Description.emplace_back(std::move(Top));
196 
197   std::string WriteResult = writeInfo(&I);
198   EXPECT_TRUE(WriteResult.size() > 0);
199   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
200 
201   CheckTypedefInfo(&I, InfoAsTypedef(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(&I2);
210   EXPECT_TRUE(WriteResult.size() > 0);
211   ReadResults = readInfo(WriteResult, 1);
212   CheckTypedefInfo(&I2, InfoAsTypedef(ReadResults[0].get()));
213 }
214 
TEST(SerializeTest,emitInfoWithCommentBitcode)215 TEST(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(TypeInfo("int"), "I");
221 
222   CommentInfo Top;
223   Top.Kind = "FullComment";
224 
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";
230 
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.";
238 
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.";
248 
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;
269 
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.";
278 
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.";
294 
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";
309 
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";
321 
322   F.Description.emplace_back(std::move(Top));
323 
324   std::string WriteResult = writeInfo(&F);
325   EXPECT_TRUE(WriteResult.size() > 0);
326   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
327 
328   CheckFunctionInfo(&F, InfoAsFunction(ReadResults[0].get()));
329 }
330 
331 } // namespace doc
332 } // namespace clang
333