• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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