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