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