1 //===-- clang-doc/SerializeTest.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 "Serialize.h"
10 #include "ClangDocTest.h"
11 #include "Representation.h"
12 #include "clang/AST/Comment.h"
13 #include "clang/AST/RecursiveASTVisitor.h"
14 #include "gtest/gtest.h"
15
16 namespace clang {
17 namespace doc {
18
19 class ClangDocSerializeTestVisitor
20 : public RecursiveASTVisitor<ClangDocSerializeTestVisitor> {
21
22 EmittedInfoList &EmittedInfos;
23 bool Public;
24
getComment(const NamedDecl * D) const25 comments::FullComment *getComment(const NamedDecl *D) const {
26 if (RawComment *Comment =
27 D->getASTContext().getRawCommentForDeclNoCache(D)) {
28 Comment->setAttached();
29 return Comment->parse(D->getASTContext(), nullptr, D);
30 }
31 return nullptr;
32 }
33
34 public:
ClangDocSerializeTestVisitor(EmittedInfoList & EmittedInfos,bool Public)35 ClangDocSerializeTestVisitor(EmittedInfoList &EmittedInfos, bool Public)
36 : EmittedInfos(EmittedInfos), Public(Public) {}
37
mapDecl(const T * D)38 template <typename T> bool mapDecl(const T *D) {
39 auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0,
40 /*File=*/"test.cpp", true, Public);
41 if (I.first)
42 EmittedInfos.emplace_back(std::move(I.first));
43 if (I.second)
44 EmittedInfos.emplace_back(std::move(I.second));
45 return true;
46 }
47
VisitNamespaceDecl(const NamespaceDecl * D)48 bool VisitNamespaceDecl(const NamespaceDecl *D) { return mapDecl(D); }
49
VisitFunctionDecl(const FunctionDecl * D)50 bool VisitFunctionDecl(const FunctionDecl *D) {
51 // Don't visit CXXMethodDecls twice
52 if (dyn_cast<CXXMethodDecl>(D))
53 return true;
54 return mapDecl(D);
55 }
56
VisitCXXMethodDecl(const CXXMethodDecl * D)57 bool VisitCXXMethodDecl(const CXXMethodDecl *D) { return mapDecl(D); }
58
VisitRecordDecl(const RecordDecl * D)59 bool VisitRecordDecl(const RecordDecl *D) { return mapDecl(D); }
60
VisitEnumDecl(const EnumDecl * D)61 bool VisitEnumDecl(const EnumDecl *D) { return mapDecl(D); }
62 };
63
ExtractInfosFromCode(StringRef Code,size_t NumExpectedInfos,bool Public,EmittedInfoList & EmittedInfos)64 void ExtractInfosFromCode(StringRef Code, size_t NumExpectedInfos, bool Public,
65 EmittedInfoList &EmittedInfos) {
66 auto ASTUnit = clang::tooling::buildASTFromCode(Code);
67 auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
68 ClangDocSerializeTestVisitor Visitor(EmittedInfos, Public);
69 Visitor.TraverseTranslationUnitDecl(TU);
70 ASSERT_EQ(NumExpectedInfos, EmittedInfos.size());
71 }
72
ExtractInfosFromCodeWithArgs(StringRef Code,size_t NumExpectedInfos,bool Public,EmittedInfoList & EmittedInfos,std::vector<std::string> & Args)73 void ExtractInfosFromCodeWithArgs(StringRef Code, size_t NumExpectedInfos,
74 bool Public, EmittedInfoList &EmittedInfos,
75 std::vector<std::string> &Args) {
76 auto ASTUnit = clang::tooling::buildASTFromCodeWithArgs(Code, Args);
77 auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
78 ClangDocSerializeTestVisitor Visitor(EmittedInfos, Public);
79 Visitor.TraverseTranslationUnitDecl(TU);
80 ASSERT_EQ(NumExpectedInfos, EmittedInfos.size());
81 }
82
83 // Test serialization of namespace declarations.
TEST(SerializeTest,emitNamespaceInfo)84 TEST(SerializeTest, emitNamespaceInfo) {
85 EmittedInfoList Infos;
86 ExtractInfosFromCode("namespace A { namespace B { void f() {} } }", 5,
87 /*Public=*/false, Infos);
88
89 NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
90 NamespaceInfo ExpectedA(EmptySID, "A");
91 CheckNamespaceInfo(&ExpectedA, A);
92
93 NamespaceInfo *B = InfoAsNamespace(Infos[2].get());
94 NamespaceInfo ExpectedB(EmptySID, /*Name=*/"B", /*Path=*/"A");
95 ExpectedB.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
96 CheckNamespaceInfo(&ExpectedB, B);
97
98 NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[4].get());
99 NamespaceInfo ExpectedBWithFunction(EmptySID);
100 FunctionInfo F;
101 F.Name = "f";
102 F.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
103 F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
104 F.Namespace.emplace_back(EmptySID, "B", InfoType::IT_namespace);
105 F.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
106 F.Access = AccessSpecifier::AS_none;
107 ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F));
108 CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
109 }
110
TEST(SerializeTest,emitAnonymousNamespaceInfo)111 TEST(SerializeTest, emitAnonymousNamespaceInfo) {
112 EmittedInfoList Infos;
113 ExtractInfosFromCode("namespace { }", 2, /*Public=*/false, Infos);
114
115 NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
116 NamespaceInfo ExpectedA(EmptySID);
117 ExpectedA.Name = "@nonymous_namespace";
118 CheckNamespaceInfo(&ExpectedA, A);
119 }
120
121 // Test serialization of record declarations.
TEST(SerializeTest,emitRecordInfo)122 TEST(SerializeTest, emitRecordInfo) {
123 EmittedInfoList Infos;
124 ExtractInfosFromCode(R"raw(class E {
125 public:
126 E() {}
127 protected:
128 void ProtectedMethod();
129 };
130 template <typename T>
131 struct F {
132 void TemplateMethod();
133 };
134 template <>
135 void F<int>::TemplateMethod();
136 typedef struct {} G;)raw",
137 10, /*Public=*/false, Infos);
138
139 RecordInfo *E = InfoAsRecord(Infos[0].get());
140 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
141 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
142 InfoType::IT_namespace);
143 ExpectedE.TagType = TagTypeKind::TTK_Class;
144 ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
145 CheckRecordInfo(&ExpectedE, E);
146
147 RecordInfo *RecordWithEConstructor = InfoAsRecord(Infos[2].get());
148 RecordInfo ExpectedRecordWithEConstructor(EmptySID);
149 FunctionInfo EConstructor;
150 EConstructor.Name = "E";
151 EConstructor.Parent = Reference(EmptySID, "E", InfoType::IT_record);
152 EConstructor.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
153 EConstructor.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
154 EConstructor.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);
155 EConstructor.Namespace.emplace_back(EmptySID, "GlobalNamespace",
156 InfoType::IT_namespace);
157 EConstructor.Access = AccessSpecifier::AS_public;
158 EConstructor.IsMethod = true;
159 ExpectedRecordWithEConstructor.ChildFunctions.emplace_back(
160 std::move(EConstructor));
161 CheckRecordInfo(&ExpectedRecordWithEConstructor, RecordWithEConstructor);
162
163 RecordInfo *RecordWithMethod = InfoAsRecord(Infos[3].get());
164 RecordInfo ExpectedRecordWithMethod(EmptySID);
165 FunctionInfo Method;
166 Method.Name = "ProtectedMethod";
167 Method.Parent = Reference(EmptySID, "E", InfoType::IT_record);
168 Method.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
169 Method.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"});
170 Method.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);
171 Method.Namespace.emplace_back(EmptySID, "GlobalNamespace",
172 InfoType::IT_namespace);
173 Method.Access = AccessSpecifier::AS_protected;
174 Method.IsMethod = true;
175 ExpectedRecordWithMethod.ChildFunctions.emplace_back(std::move(Method));
176 CheckRecordInfo(&ExpectedRecordWithMethod, RecordWithMethod);
177
178 RecordInfo *F = InfoAsRecord(Infos[4].get());
179 RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
180 ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace",
181 InfoType::IT_namespace);
182 ExpectedF.TagType = TagTypeKind::TTK_Struct;
183 ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
184 CheckRecordInfo(&ExpectedF, F);
185
186 RecordInfo *RecordWithTemplateMethod = InfoAsRecord(Infos[6].get());
187 RecordInfo ExpectedRecordWithTemplateMethod(EmptySID);
188 FunctionInfo TemplateMethod;
189 TemplateMethod.Name = "TemplateMethod";
190 TemplateMethod.Parent = Reference(EmptySID, "F", InfoType::IT_record);
191 TemplateMethod.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
192 TemplateMethod.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"});
193 TemplateMethod.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);
194 TemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace",
195 InfoType::IT_namespace);
196 TemplateMethod.Access = AccessSpecifier::AS_public;
197 TemplateMethod.IsMethod = true;
198 ExpectedRecordWithTemplateMethod.ChildFunctions.emplace_back(
199 std::move(TemplateMethod));
200 CheckRecordInfo(&ExpectedRecordWithTemplateMethod, RecordWithTemplateMethod);
201
202 RecordInfo *TemplatedRecord = InfoAsRecord(Infos[7].get());
203 RecordInfo ExpectedTemplatedRecord(EmptySID);
204 FunctionInfo SpecializedTemplateMethod;
205 SpecializedTemplateMethod.Name = "TemplateMethod";
206 SpecializedTemplateMethod.Parent =
207 Reference(EmptySID, "F", InfoType::IT_record);
208 SpecializedTemplateMethod.ReturnType =
209 TypeInfo(EmptySID, "void", InfoType::IT_default);
210 SpecializedTemplateMethod.Loc.emplace_back(0,
211 llvm::SmallString<16>{"test.cpp"});
212 SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "F",
213 InfoType::IT_record);
214 SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace",
215 InfoType::IT_namespace);
216 SpecializedTemplateMethod.Access = AccessSpecifier::AS_public;
217 SpecializedTemplateMethod.IsMethod = true;
218 ExpectedTemplatedRecord.ChildFunctions.emplace_back(
219 std::move(SpecializedTemplateMethod));
220 CheckRecordInfo(&ExpectedTemplatedRecord, TemplatedRecord);
221
222 RecordInfo *G = InfoAsRecord(Infos[8].get());
223 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");
224 ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",
225 InfoType::IT_namespace);
226 ExpectedG.TagType = TagTypeKind::TTK_Struct;
227 ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
228 ExpectedG.IsTypeDef = true;
229 CheckRecordInfo(&ExpectedG, G);
230 }
231
232 // Test serialization of enum declarations.
TEST(SerializeTest,emitEnumInfo)233 TEST(SerializeTest, emitEnumInfo) {
234 EmittedInfoList Infos;
235 ExtractInfosFromCode("enum E { X, Y }; enum class G { A, B };", 2,
236 /*Public=*/false, Infos);
237
238 NamespaceInfo *NamespaceWithEnum = InfoAsNamespace(Infos[0].get());
239 NamespaceInfo ExpectedNamespaceWithEnum(EmptySID);
240 EnumInfo E;
241 E.Name = "E";
242 E.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
243 E.Members.emplace_back("X");
244 E.Members.emplace_back("Y");
245 ExpectedNamespaceWithEnum.ChildEnums.emplace_back(std::move(E));
246 CheckNamespaceInfo(&ExpectedNamespaceWithEnum, NamespaceWithEnum);
247
248 NamespaceInfo *NamespaceWithScopedEnum = InfoAsNamespace(Infos[1].get());
249 NamespaceInfo ExpectedNamespaceWithScopedEnum(EmptySID);
250 EnumInfo G;
251 G.Name = "G";
252 G.Scoped = true;
253 G.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
254 G.Members.emplace_back("A");
255 G.Members.emplace_back("B");
256 ExpectedNamespaceWithScopedEnum.ChildEnums.emplace_back(std::move(G));
257 CheckNamespaceInfo(&ExpectedNamespaceWithScopedEnum, NamespaceWithScopedEnum);
258 }
259
TEST(SerializeTest,emitUndefinedRecordInfo)260 TEST(SerializeTest, emitUndefinedRecordInfo) {
261 EmittedInfoList Infos;
262 ExtractInfosFromCode("class E;", 2, /*Public=*/false, Infos);
263
264 RecordInfo *E = InfoAsRecord(Infos[0].get());
265 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
266 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
267 InfoType::IT_namespace);
268 ExpectedE.TagType = TagTypeKind::TTK_Class;
269 ExpectedE.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"});
270 CheckRecordInfo(&ExpectedE, E);
271 }
272
TEST(SerializeTest,emitRecordMemberInfo)273 TEST(SerializeTest, emitRecordMemberInfo) {
274 EmittedInfoList Infos;
275 ExtractInfosFromCode("struct E { int I; };", 2, /*Public=*/false, Infos);
276
277 RecordInfo *E = InfoAsRecord(Infos[0].get());
278 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
279 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
280 InfoType::IT_namespace);
281 ExpectedE.TagType = TagTypeKind::TTK_Struct;
282 ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
283 ExpectedE.Members.emplace_back("int", "I", AccessSpecifier::AS_public);
284 CheckRecordInfo(&ExpectedE, E);
285 }
286
TEST(SerializeTest,emitInternalRecordInfo)287 TEST(SerializeTest, emitInternalRecordInfo) {
288 EmittedInfoList Infos;
289 ExtractInfosFromCode("class E { class G {}; };", 4, /*Public=*/false, Infos);
290
291 RecordInfo *E = InfoAsRecord(Infos[0].get());
292 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
293 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
294 InfoType::IT_namespace);
295 ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
296 ExpectedE.TagType = TagTypeKind::TTK_Class;
297 CheckRecordInfo(&ExpectedE, E);
298
299 RecordInfo *G = InfoAsRecord(Infos[2].get());
300 llvm::SmallString<128> ExpectedGPath("GlobalNamespace/E");
301 llvm::sys::path::native(ExpectedGPath);
302 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/ExpectedGPath);
303 ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
304 ExpectedG.TagType = TagTypeKind::TTK_Class;
305 ExpectedG.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);
306 ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",
307 InfoType::IT_namespace);
308 CheckRecordInfo(&ExpectedG, G);
309 }
310
TEST(SerializeTest,emitPublicAnonymousNamespaceInfo)311 TEST(SerializeTest, emitPublicAnonymousNamespaceInfo) {
312 EmittedInfoList Infos;
313 ExtractInfosFromCode("namespace { class A; }", 0, /*Public=*/true, Infos);
314 }
315
TEST(SerializeTest,emitPublicFunctionInternalInfo)316 TEST(SerializeTest, emitPublicFunctionInternalInfo) {
317 EmittedInfoList Infos;
318 ExtractInfosFromCode("int F() { class G {}; return 0; };", 1, /*Public=*/true,
319 Infos);
320
321 NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
322 NamespaceInfo ExpectedBWithFunction(EmptySID);
323 FunctionInfo F;
324 F.Name = "F";
325 F.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default);
326 F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
327 F.Access = AccessSpecifier::AS_none;
328 ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F));
329 CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
330 }
331
TEST(SerializeTest,emitInlinedFunctionInfo)332 TEST(SerializeTest, emitInlinedFunctionInfo) {
333 EmittedInfoList Infos;
334 ExtractInfosFromCode("inline void F(int I) { };", 1, /*Public=*/true, Infos);
335
336 NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
337 NamespaceInfo ExpectedBWithFunction(EmptySID);
338 FunctionInfo F;
339 F.Name = "F";
340 F.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
341 F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
342 F.Params.emplace_back("int", "I");
343 F.Access = AccessSpecifier::AS_none;
344 ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F));
345 CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
346 }
347
TEST(SerializeTest,emitInheritedRecordInfo)348 TEST(SerializeTest, emitInheritedRecordInfo) {
349 EmittedInfoList Infos;
350 ExtractInfosFromCode(R"raw(class F { protected: void set(int N); };
351 class G { public: int get() { return 1; } protected: int I; };
352 class E : public F, virtual private G {};
353 class H : private E {};
354 template <typename T>
355 class I {} ;
356 class J : public I<int> {} ;)raw",
357 14, /*Public=*/false, Infos);
358
359 RecordInfo *F = InfoAsRecord(Infos[0].get());
360 RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
361 ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace",
362 InfoType::IT_namespace);
363 ExpectedF.TagType = TagTypeKind::TTK_Class;
364 ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
365 CheckRecordInfo(&ExpectedF, F);
366
367 RecordInfo *G = InfoAsRecord(Infos[3].get());
368 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");
369 ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",
370 InfoType::IT_namespace);
371 ExpectedG.TagType = TagTypeKind::TTK_Class;
372 ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
373 ExpectedG.Members.emplace_back("int", "I", AccessSpecifier::AS_protected);
374 CheckRecordInfo(&ExpectedG, G);
375
376 RecordInfo *E = InfoAsRecord(Infos[6].get());
377 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
378 ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
379 InfoType::IT_namespace);
380 ExpectedE.Parents.emplace_back(EmptySID, /*Name=*/"F", InfoType::IT_record,
381 /*Path*=*/"GlobalNamespace");
382 ExpectedE.VirtualParents.emplace_back(
383 EmptySID, /*Name=*/"G", InfoType::IT_record, /*Path*=*/"GlobalNamespace");
384 ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"F",
385 /*Path=*/"GlobalNamespace", false,
386 AccessSpecifier::AS_public, true);
387 FunctionInfo FunctionSet;
388 FunctionSet.Name = "set";
389 FunctionSet.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
390 FunctionSet.Loc.emplace_back();
391 FunctionSet.Params.emplace_back("int", "N");
392 FunctionSet.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);
393 FunctionSet.Namespace.emplace_back(EmptySID, "GlobalNamespace",
394 InfoType::IT_namespace);
395 FunctionSet.Access = AccessSpecifier::AS_protected;
396 FunctionSet.IsMethod = true;
397 ExpectedE.Bases.back().ChildFunctions.emplace_back(std::move(FunctionSet));
398 ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"G",
399 /*Path=*/"GlobalNamespace", true,
400 AccessSpecifier::AS_private, true);
401 FunctionInfo FunctionGet;
402 FunctionGet.Name = "get";
403 FunctionGet.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default);
404 FunctionGet.DefLoc = Location();
405 FunctionGet.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record);
406 FunctionGet.Namespace.emplace_back(EmptySID, "GlobalNamespace",
407 InfoType::IT_namespace);
408 FunctionGet.Access = AccessSpecifier::AS_private;
409 FunctionGet.IsMethod = true;
410 ExpectedE.Bases.back().ChildFunctions.emplace_back(std::move(FunctionGet));
411 ExpectedE.Bases.back().Members.emplace_back("int", "I",
412 AccessSpecifier::AS_private);
413 ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
414 ExpectedE.TagType = TagTypeKind::TTK_Class;
415 CheckRecordInfo(&ExpectedE, E);
416
417 RecordInfo *H = InfoAsRecord(Infos[8].get());
418 RecordInfo ExpectedH(EmptySID, /*Name=*/"H", /*Path=*/"GlobalNamespace");
419 ExpectedH.Namespace.emplace_back(EmptySID, "GlobalNamespace",
420 InfoType::IT_namespace);
421 ExpectedH.TagType = TagTypeKind::TTK_Class;
422 ExpectedH.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
423 ExpectedH.Parents.emplace_back(EmptySID, /*Name=*/"E", InfoType::IT_record,
424 /*Path=*/"GlobalNamespace");
425 ExpectedH.VirtualParents.emplace_back(
426 EmptySID, /*Name=*/"G", InfoType::IT_record, /*Path=*/"GlobalNamespace");
427 ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"E",
428 /*Path=*/"GlobalNamespace", false,
429 AccessSpecifier::AS_private, true);
430 ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"F",
431 /*Path=*/"GlobalNamespace", false,
432 AccessSpecifier::AS_private, false);
433 FunctionInfo FunctionSetNew;
434 FunctionSetNew.Name = "set";
435 FunctionSetNew.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
436 FunctionSetNew.Loc.emplace_back();
437 FunctionSetNew.Params.emplace_back("int", "N");
438 FunctionSetNew.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);
439 FunctionSetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace",
440 InfoType::IT_namespace);
441 FunctionSetNew.Access = AccessSpecifier::AS_private;
442 FunctionSetNew.IsMethod = true;
443 ExpectedH.Bases.back().ChildFunctions.emplace_back(std::move(FunctionSetNew));
444 ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"G",
445 /*Path=*/"GlobalNamespace", true,
446 AccessSpecifier::AS_private, false);
447 FunctionInfo FunctionGetNew;
448 FunctionGetNew.Name = "get";
449 FunctionGetNew.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default);
450 FunctionGetNew.DefLoc = Location();
451 FunctionGetNew.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record);
452 FunctionGetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace",
453 InfoType::IT_namespace);
454 FunctionGetNew.Access = AccessSpecifier::AS_private;
455 FunctionGetNew.IsMethod = true;
456 ExpectedH.Bases.back().ChildFunctions.emplace_back(std::move(FunctionGetNew));
457 ExpectedH.Bases.back().Members.emplace_back("int", "I",
458 AccessSpecifier::AS_private);
459 CheckRecordInfo(&ExpectedH, H);
460
461 RecordInfo *I = InfoAsRecord(Infos[10].get());
462 RecordInfo ExpectedI(EmptySID, /*Name=*/"I", /*Path=*/"GlobalNamespace");
463 ExpectedI.Namespace.emplace_back(EmptySID, "GlobalNamespace",
464 InfoType::IT_namespace);
465 ExpectedI.TagType = TagTypeKind::TTK_Class;
466 ExpectedI.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
467 CheckRecordInfo(&ExpectedI, I);
468
469 RecordInfo *J = InfoAsRecord(Infos[12].get());
470 RecordInfo ExpectedJ(EmptySID, /*Name=*/"J", /*Path=*/"GlobalNamespace");
471 ExpectedJ.Namespace.emplace_back(EmptySID, "GlobalNamespace",
472 InfoType::IT_namespace);
473 ExpectedJ.Parents.emplace_back(EmptySID, /*Name=*/"I<int>",
474 InfoType::IT_record);
475 ExpectedJ.Bases.emplace_back(EmptySID, /*Name=*/"I<int>",
476 /*Path=*/"GlobalNamespace", false,
477 AccessSpecifier::AS_public, true);
478 ExpectedJ.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
479 ExpectedJ.TagType = TagTypeKind::TTK_Class;
480 CheckRecordInfo(&ExpectedJ, J);
481 }
482
TEST(SerializeTest,emitModulePublicLFunctions)483 TEST(SerializeTest, emitModulePublicLFunctions) {
484 EmittedInfoList Infos;
485 std::vector<std::string> Args;
486 Args.push_back("-fmodules-ts");
487 ExtractInfosFromCodeWithArgs(R"raw(export module M;
488 int moduleFunction(int x);
489 static int staticModuleFunction(int x);
490 export double exportedModuleFunction(double y);)raw",
491 2, /*Public=*/true, Infos, Args);
492
493 NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
494 NamespaceInfo ExpectedBWithFunction(EmptySID);
495 FunctionInfo F;
496 F.Name = "moduleFunction";
497 F.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default);
498 F.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"});
499 F.Params.emplace_back("int", "x");
500 F.Access = AccessSpecifier::AS_none;
501 ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F));
502 CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
503
504 NamespaceInfo *BWithExportedFunction = InfoAsNamespace(Infos[1].get());
505 NamespaceInfo ExpectedBWithExportedFunction(EmptySID);
506 FunctionInfo ExportedF;
507 ExportedF.Name = "exportedModuleFunction";
508 ExportedF.ReturnType = TypeInfo(EmptySID, "double", InfoType::IT_default);
509 ExportedF.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"});
510 ExportedF.Params.emplace_back("double", "y");
511 ExportedF.Access = AccessSpecifier::AS_none;
512 ExpectedBWithExportedFunction.ChildFunctions.emplace_back(
513 std::move(ExportedF));
514 CheckNamespaceInfo(&ExpectedBWithExportedFunction, BWithExportedFunction);
515 }
516
517 // Test serialization of child records in namespaces and other records
TEST(SerializeTest,emitChildRecords)518 TEST(SerializeTest, emitChildRecords) {
519 EmittedInfoList Infos;
520 ExtractInfosFromCode("class A { class B {}; }; namespace { class C {}; } ", 8,
521 /*Public=*/false, Infos);
522
523 NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
524 NamespaceInfo ExpectedParentA(EmptySID);
525 ExpectedParentA.ChildRecords.emplace_back(EmptySID, "A", InfoType::IT_record,
526 "GlobalNamespace");
527 CheckNamespaceInfo(&ExpectedParentA, ParentA);
528
529 RecordInfo *ParentB = InfoAsRecord(Infos[3].get());
530 RecordInfo ExpectedParentB(EmptySID);
531 llvm::SmallString<128> ExpectedParentBPath("GlobalNamespace/A");
532 llvm::sys::path::native(ExpectedParentBPath);
533 ExpectedParentB.ChildRecords.emplace_back(EmptySID, "B", InfoType::IT_record,
534 ExpectedParentBPath);
535 CheckRecordInfo(&ExpectedParentB, ParentB);
536
537 NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get());
538 NamespaceInfo ExpectedParentC(EmptySID);
539 ExpectedParentC.ChildRecords.emplace_back(EmptySID, "C", InfoType::IT_record,
540 "@nonymous_namespace");
541 CheckNamespaceInfo(&ExpectedParentC, ParentC);
542 }
543
544 // Test serialization of child namespaces
TEST(SerializeTest,emitChildNamespaces)545 TEST(SerializeTest, emitChildNamespaces) {
546 EmittedInfoList Infos;
547 ExtractInfosFromCode("namespace A { namespace B { } }", 4, /*Public=*/false,
548 Infos);
549
550 NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
551 NamespaceInfo ExpectedParentA(EmptySID);
552 ExpectedParentA.ChildNamespaces.emplace_back(EmptySID, "A",
553 InfoType::IT_namespace);
554 CheckNamespaceInfo(&ExpectedParentA, ParentA);
555
556 NamespaceInfo *ParentB = InfoAsNamespace(Infos[3].get());
557 NamespaceInfo ExpectedParentB(EmptySID);
558 ExpectedParentB.ChildNamespaces.emplace_back(EmptySID, "B",
559 InfoType::IT_namespace, "A");
560 CheckNamespaceInfo(&ExpectedParentB, ParentB);
561 }
562
563 } // namespace doc
564 } // end namespace clang
565