1 //===-- clang-doc/BitcodeTest.cpp -----------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "BitcodeReader.h"
11 #include "BitcodeWriter.h"
12 #include "ClangDocTest.h"
13 #include "Representation.h"
14 #include "llvm/Bitcode/BitstreamReader.h"
15 #include "llvm/Bitcode/BitstreamWriter.h"
16 #include "gtest/gtest.h"
17 
18 namespace clang {
19 namespace doc {
20 
21 template <typename T> static std::string writeInfo(T &I) {
22   SmallString<2048> Buffer;
23   llvm::BitstreamWriter Stream(Buffer);
24   ClangDocBitcodeWriter Writer(Stream);
25   Writer.emitBlock(I);
26   return Buffer.str().str();
27 }
28 
29 std::string writeInfo(Info *I) {
30   switch (I->IT) {
31   case InfoType::IT_namespace:
32     return writeInfo(*static_cast<NamespaceInfo *>(I));
33   case InfoType::IT_record:
34     return writeInfo(*static_cast<RecordInfo *>(I));
35   case InfoType::IT_enum:
36     return writeInfo(*static_cast<EnumInfo *>(I));
37   case InfoType::IT_function:
38     return writeInfo(*static_cast<FunctionInfo *>(I));
39   default:
40     return "";
41   }
42 }
43 
44 std::vector<std::unique_ptr<Info>> readInfo(StringRef Bitcode,
45                                             size_t NumInfos) {
46   llvm::BitstreamCursor Stream(Bitcode);
47   doc::ClangDocBitcodeReader Reader(Stream);
48   auto Infos = Reader.readBitcode();
49 
50   // Check that there was no error in the read.
51   assert(Infos);
52   EXPECT_EQ(Infos.get().size(), NumInfos);
53   return std::move(Infos.get());
54 }
55 
56 TEST(BitcodeTest, emitNamespaceInfoBitcode) {
57   NamespaceInfo I;
58   I.Name = "r";
59   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
60 
61   I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
62                                  InfoType::IT_namespace);
63   I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
64   I.ChildFunctions.emplace_back();
65   I.ChildEnums.emplace_back();
66 
67   std::string WriteResult = writeInfo(&I);
68   EXPECT_TRUE(WriteResult.size() > 0);
69   std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
70 
71   CheckNamespaceInfo(&I, InfoAsNamespace(ReadResults[0].get()));
72 }
73 
74 TEST(BitcodeTest, emitRecordInfoBitcode) {
75   RecordInfo I;
76   I.Name = "r";
77   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
78 
79   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
80   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
81 
82   I.Members.emplace_back("int", "X", AccessSpecifier::AS_private);
83   I.TagType = TagTypeKind::TTK_Class;
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