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 
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 
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   default:
39     return "";
40   }
41 }
42 
43 std::vector<std::unique_ptr<Info>> readInfo(StringRef Bitcode,
44                                             size_t NumInfos) {
45   llvm::BitstreamCursor Stream(Bitcode);
46   doc::ClangDocBitcodeReader Reader(Stream);
47   auto Infos = Reader.readBitcode();
48 
49   // Check that there was no error in the read.
50   assert(Infos);
51   EXPECT_EQ(Infos.get().size(), NumInfos);
52   return std::move(Infos.get());
53 }
54 
55 TEST(BitcodeTest, emitNamespaceInfoBitcode) {
56   NamespaceInfo I;
57   I.Name = "r";
58   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
59 
60   I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
61                                  InfoType::IT_namespace);
62   I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
63   I.ChildFunctions.emplace_back();
64   I.ChildEnums.emplace_back();
65 
66   std::string WriteResult = writeInfo(&I);
67   EXPECT_TRUE(WriteResult.size() > 0);
68   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
69 
70   CheckNamespaceInfo(&I, InfoAsNamespace(ReadResults[0].get()));
71 }
72 
73 TEST(BitcodeTest, emitRecordInfoBitcode) {
74   RecordInfo I;
75   I.Name = "r";
76   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
77 
78   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
79   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
80 
81   I.Members.emplace_back("int", "X", AccessSpecifier::AS_private);
82   I.TagType = TagTypeKind::TTK_Class;
83   I.IsTypeDef = true;
84   I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
85   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
86 
87   I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
88   I.ChildFunctions.emplace_back();
89   I.ChildEnums.emplace_back();
90 
91   std::string WriteResult = writeInfo(&I);
92   EXPECT_TRUE(WriteResult.size() > 0);
93   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
94 
95   CheckRecordInfo(&I, InfoAsRecord(ReadResults[0].get()));
96 }
97 
98 TEST(BitcodeTest, emitFunctionInfoBitcode) {
99   FunctionInfo I;
100   I.Name = "f";
101   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
102 
103   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
104   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
105 
106   I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
107   I.Params.emplace_back("int", "P");
108 
109   std::string WriteResult = writeInfo(&I);
110   EXPECT_TRUE(WriteResult.size() > 0);
111   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
112 
113   CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get()));
114 }
115 
116 TEST(BitcodeTest, emitMethodInfoBitcode) {
117   FunctionInfo I;
118   I.Name = "f";
119   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
120 
121   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
122   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
123 
124   I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
125   I.Params.emplace_back("int", "P");
126   I.IsMethod = true;
127   I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
128 
129   // TODO: fix access
130   // I.Access = AccessSpecifier::AS_private;
131 
132   std::string WriteResult = writeInfo(&I);
133   EXPECT_TRUE(WriteResult.size() > 0);
134   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
135 
136   CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get()));
137 }
138 
139 TEST(BitcodeTest, emitEnumInfoBitcode) {
140   EnumInfo I;
141   I.Name = "e";
142   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
143 
144   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
145   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
146 
147   I.Members.emplace_back("X");
148   I.Scoped = true;
149 
150   std::string WriteResult = writeInfo(&I);
151   EXPECT_TRUE(WriteResult.size() > 0);
152   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
153 
154   CheckEnumInfo(&I, InfoAsEnum(ReadResults[0].get()));
155 }
156 
157 TEST(SerializeTest, emitInfoWithCommentBitcode) {
158   FunctionInfo F;
159   F.Name = "F";
160   F.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
161   F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
162   F.Params.emplace_back("int", "I");
163 
164   CommentInfo Top;
165   Top.Kind = "FullComment";
166 
167   Top.Children.emplace_back(llvm::make_unique<CommentInfo>());
168   CommentInfo *BlankLine = Top.Children.back().get();
169   BlankLine->Kind = "ParagraphComment";
170   BlankLine->Children.emplace_back(llvm::make_unique<CommentInfo>());
171   BlankLine->Children.back()->Kind = "TextComment";
172 
173   Top.Children.emplace_back(llvm::make_unique<CommentInfo>());
174   CommentInfo *Brief = Top.Children.back().get();
175   Brief->Kind = "ParagraphComment";
176   Brief->Children.emplace_back(llvm::make_unique<CommentInfo>());
177   Brief->Children.back()->Kind = "TextComment";
178   Brief->Children.back()->Name = "ParagraphComment";
179   Brief->Children.back()->Text = " Brief description.";
180 
181   Top.Children.emplace_back(llvm::make_unique<CommentInfo>());
182   CommentInfo *Extended = Top.Children.back().get();
183   Extended->Kind = "ParagraphComment";
184   Extended->Children.emplace_back(llvm::make_unique<CommentInfo>());
185   Extended->Children.back()->Kind = "TextComment";
186   Extended->Children.back()->Text = " Extended description that";
187   Extended->Children.emplace_back(llvm::make_unique<CommentInfo>());
188   Extended->Children.back()->Kind = "TextComment";
189   Extended->Children.back()->Text = " continues onto the next line.";
190 
191   Top.Children.emplace_back(llvm::make_unique<CommentInfo>());
192   CommentInfo *HTML = Top.Children.back().get();
193   HTML->Kind = "ParagraphComment";
194   HTML->Children.emplace_back(llvm::make_unique<CommentInfo>());
195   HTML->Children.back()->Kind = "TextComment";
196   HTML->Children.emplace_back(llvm::make_unique<CommentInfo>());
197   HTML->Children.back()->Kind = "HTMLStartTagComment";
198   HTML->Children.back()->Name = "ul";
199   HTML->Children.back()->AttrKeys.emplace_back("class");
200   HTML->Children.back()->AttrValues.emplace_back("test");
201   HTML->Children.emplace_back(llvm::make_unique<CommentInfo>());
202   HTML->Children.back()->Kind = "HTMLStartTagComment";
203   HTML->Children.back()->Name = "li";
204   HTML->Children.emplace_back(llvm::make_unique<CommentInfo>());
205   HTML->Children.back()->Kind = "TextComment";
206   HTML->Children.back()->Text = " Testing.";
207   HTML->Children.emplace_back(llvm::make_unique<CommentInfo>());
208   HTML->Children.back()->Kind = "HTMLEndTagComment";
209   HTML->Children.back()->Name = "ul";
210   HTML->Children.back()->SelfClosing = true;
211 
212   Top.Children.emplace_back(llvm::make_unique<CommentInfo>());
213   CommentInfo *Verbatim = Top.Children.back().get();
214   Verbatim->Kind = "VerbatimBlockComment";
215   Verbatim->Name = "verbatim";
216   Verbatim->CloseName = "endverbatim";
217   Verbatim->Children.emplace_back(llvm::make_unique<CommentInfo>());
218   Verbatim->Children.back()->Kind = "VerbatimBlockLineComment";
219   Verbatim->Children.back()->Text = " The description continues.";
220 
221   Top.Children.emplace_back(llvm::make_unique<CommentInfo>());
222   CommentInfo *ParamOut = Top.Children.back().get();
223   ParamOut->Kind = "ParamCommandComment";
224   ParamOut->Direction = "[out]";
225   ParamOut->ParamName = "I";
226   ParamOut->Explicit = true;
227   ParamOut->Children.emplace_back(llvm::make_unique<CommentInfo>());
228   ParamOut->Children.back()->Kind = "ParagraphComment";
229   ParamOut->Children.back()->Children.emplace_back(
230       llvm::make_unique<CommentInfo>());
231   ParamOut->Children.back()->Children.back()->Kind = "TextComment";
232   ParamOut->Children.back()->Children.emplace_back(
233       llvm::make_unique<CommentInfo>());
234   ParamOut->Children.back()->Children.back()->Kind = "TextComment";
235   ParamOut->Children.back()->Children.back()->Text = " is a parameter.";
236 
237   Top.Children.emplace_back(llvm::make_unique<CommentInfo>());
238   CommentInfo *ParamIn = Top.Children.back().get();
239   ParamIn->Kind = "ParamCommandComment";
240   ParamIn->Direction = "[in]";
241   ParamIn->ParamName = "J";
242   ParamIn->Children.emplace_back(llvm::make_unique<CommentInfo>());
243   ParamIn->Children.back()->Kind = "ParagraphComment";
244   ParamIn->Children.back()->Children.emplace_back(
245       llvm::make_unique<CommentInfo>());
246   ParamIn->Children.back()->Children.back()->Kind = "TextComment";
247   ParamIn->Children.back()->Children.back()->Text = " is a parameter.";
248   ParamIn->Children.back()->Children.emplace_back(
249       llvm::make_unique<CommentInfo>());
250   ParamIn->Children.back()->Children.back()->Kind = "TextComment";
251 
252   Top.Children.emplace_back(llvm::make_unique<CommentInfo>());
253   CommentInfo *Return = Top.Children.back().get();
254   Return->Kind = "BlockCommandComment";
255   Return->Name = "return";
256   Return->Explicit = true;
257   Return->Children.emplace_back(llvm::make_unique<CommentInfo>());
258   Return->Children.back()->Kind = "ParagraphComment";
259   Return->Children.back()->Children.emplace_back(
260       llvm::make_unique<CommentInfo>());
261   Return->Children.back()->Children.back()->Kind = "TextComment";
262   Return->Children.back()->Children.back()->Text = "void";
263 
264   F.Description.emplace_back(std::move(Top));
265 
266   std::string WriteResult = writeInfo(&F);
267   EXPECT_TRUE(WriteResult.size() > 0);
268   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
269 
270   CheckFunctionInfo(&F, InfoAsFunction(ReadResults[0].get()));
271 }
272 
273 } // namespace doc
274 } // namespace clang
275