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