xref: /llvm-project/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp (revision 2b932bc111c0d96db7044b0a854d7ad763710df2)
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 
25   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:
35   ClangDocSerializeTestVisitor(EmittedInfoList &EmittedInfos, bool Public)
36       : EmittedInfos(EmittedInfos), Public(Public) {}
37 
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 
48   bool VisitNamespaceDecl(const NamespaceDecl *D) { return mapDecl(D); }
49 
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 
57   bool VisitCXXMethodDecl(const CXXMethodDecl *D) { return mapDecl(D); }
58 
59   bool VisitRecordDecl(const RecordDecl *D) { return mapDecl(D); }
60 
61   bool VisitEnumDecl(const EnumDecl *D) { return mapDecl(D); }
62 
63   bool VisitTypedefDecl(const TypedefDecl *D) { return mapDecl(D); }
64 
65   bool VisitTypeAliasDecl(const TypeAliasDecl *D) { return mapDecl(D); }
66 };
67 
68 void ExtractInfosFromCode(StringRef Code, size_t NumExpectedInfos, bool Public,
69                           EmittedInfoList &EmittedInfos) {
70   auto ASTUnit = clang::tooling::buildASTFromCode(Code);
71   auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
72   ClangDocSerializeTestVisitor Visitor(EmittedInfos, Public);
73   Visitor.TraverseTranslationUnitDecl(TU);
74   ASSERT_EQ(NumExpectedInfos, EmittedInfos.size());
75 }
76 
77 void ExtractInfosFromCodeWithArgs(StringRef Code, size_t NumExpectedInfos,
78                                   bool Public, EmittedInfoList &EmittedInfos,
79                                   std::vector<std::string> &Args) {
80   auto ASTUnit = clang::tooling::buildASTFromCodeWithArgs(Code, Args);
81   auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
82   ClangDocSerializeTestVisitor Visitor(EmittedInfos, Public);
83   Visitor.TraverseTranslationUnitDecl(TU);
84   ASSERT_EQ(NumExpectedInfos, EmittedInfos.size());
85 }
86 
87 // Constructs a comment definition as the parser would for one comment line.
88 /* TODO uncomment this when the missing comment is fixed in emitRecordInfo and
89    the code that calls this is re-enabled.
90 CommentInfo MakeOneLineCommentInfo(const std::string &Text) {
91   CommentInfo TopComment;
92   TopComment.Kind = "FullComment";
93   TopComment.Children.emplace_back(std::make_unique<CommentInfo>());
94 
95   CommentInfo *Brief = TopComment.Children.back().get();
96   Brief->Kind = "ParagraphComment";
97 
98   Brief->Children.emplace_back(std::make_unique<CommentInfo>());
99   Brief->Children.back()->Kind = "TextComment";
100   Brief->Children.back()->Name = "ParagraphComment";
101   Brief->Children.back()->Text = Text;
102 
103   return TopComment;
104 }
105 */
106 
107 // Test serialization of namespace declarations.
108 TEST(SerializeTest, emitNamespaceInfo) {
109   EmittedInfoList Infos;
110   ExtractInfosFromCode("namespace A { namespace B { void f() {} } }", 5,
111                        /*Public=*/false, Infos);
112 
113   NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
114   NamespaceInfo ExpectedA(EmptySID, "A");
115   CheckNamespaceInfo(&ExpectedA, A);
116 
117   NamespaceInfo *B = InfoAsNamespace(Infos[2].get());
118   NamespaceInfo ExpectedB(EmptySID, /*Name=*/"B", /*Path=*/"A");
119   ExpectedB.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
120   CheckNamespaceInfo(&ExpectedB, B);
121 
122   NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[4].get());
123   NamespaceInfo ExpectedBWithFunction(EmptySID);
124   FunctionInfo F;
125   F.Name = "f";
126   F.ReturnType = TypeInfo("void");
127   F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
128   F.Namespace.emplace_back(EmptySID, "B", InfoType::IT_namespace);
129   F.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
130   F.Access = AccessSpecifier::AS_none;
131   ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
132   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
133 }
134 
135 TEST(SerializeTest, emitAnonymousNamespaceInfo) {
136   EmittedInfoList Infos;
137   ExtractInfosFromCode("namespace { }", 2, /*Public=*/false, Infos);
138 
139   NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
140   NamespaceInfo ExpectedA(EmptySID);
141   ExpectedA.Name = "@nonymous_namespace";
142   CheckNamespaceInfo(&ExpectedA, A);
143 }
144 
145 // Test serialization of record declarations.
146 TEST(SerializeTest, emitRecordInfo) {
147   EmittedInfoList Infos;
148   ExtractInfosFromCode(R"raw(class E {
149 public:
150   E() {}
151 
152   // Some docs.
153   int value;
154 protected:
155   void ProtectedMethod();
156 };
157 template <typename T>
158 struct F {
159   void TemplateMethod();
160 };
161 template <>
162 void F<int>::TemplateMethod();
163 typedef struct {} G;)raw",
164                        10, /*Public=*/false, Infos);
165 
166   RecordInfo *E = InfoAsRecord(Infos[0].get());
167   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
168   ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
169                                    InfoType::IT_namespace);
170   ExpectedE.TagType = TagTypeKind::Class;
171   ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
172   ExpectedE.Members.emplace_back(TypeInfo("int"), "value",
173                                  AccessSpecifier::AS_public);
174   // TODO the data member should have the docstring on it:
175   //ExpectedE.Members.back().Description.push_back(MakeOneLineCommentInfo(" Some docs"));
176   CheckRecordInfo(&ExpectedE, E);
177 
178   RecordInfo *RecordWithEConstructor = InfoAsRecord(Infos[2].get());
179   RecordInfo ExpectedRecordWithEConstructor(EmptySID);
180   FunctionInfo EConstructor;
181   EConstructor.Name = "E";
182   EConstructor.Parent = Reference(EmptySID, "E", InfoType::IT_record);
183   EConstructor.ReturnType = TypeInfo("void");
184   EConstructor.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
185   EConstructor.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);
186   EConstructor.Namespace.emplace_back(EmptySID, "GlobalNamespace",
187                                       InfoType::IT_namespace);
188   EConstructor.Access = AccessSpecifier::AS_public;
189   EConstructor.IsMethod = true;
190   ExpectedRecordWithEConstructor.Children.Functions.emplace_back(
191       std::move(EConstructor));
192   CheckRecordInfo(&ExpectedRecordWithEConstructor, RecordWithEConstructor);
193 
194   RecordInfo *RecordWithMethod = InfoAsRecord(Infos[3].get());
195   RecordInfo ExpectedRecordWithMethod(EmptySID);
196   FunctionInfo Method;
197   Method.Name = "ProtectedMethod";
198   Method.Parent = Reference(EmptySID, "E", InfoType::IT_record);
199   Method.ReturnType = TypeInfo("void");
200   Method.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"});
201   Method.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);
202   Method.Namespace.emplace_back(EmptySID, "GlobalNamespace",
203                                 InfoType::IT_namespace);
204   Method.Access = AccessSpecifier::AS_protected;
205   Method.IsMethod = true;
206   ExpectedRecordWithMethod.Children.Functions.emplace_back(std::move(Method));
207   CheckRecordInfo(&ExpectedRecordWithMethod, RecordWithMethod);
208 
209   RecordInfo *F = InfoAsRecord(Infos[4].get());
210   RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
211   ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace",
212                                    InfoType::IT_namespace);
213   ExpectedF.TagType = TagTypeKind::Struct;
214   ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
215   CheckRecordInfo(&ExpectedF, F);
216 
217   RecordInfo *RecordWithTemplateMethod = InfoAsRecord(Infos[6].get());
218   RecordInfo ExpectedRecordWithTemplateMethod(EmptySID);
219   FunctionInfo TemplateMethod;
220   TemplateMethod.Name = "TemplateMethod";
221   TemplateMethod.Parent = Reference(EmptySID, "F", InfoType::IT_record);
222   TemplateMethod.ReturnType = TypeInfo("void");
223   TemplateMethod.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"});
224   TemplateMethod.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);
225   TemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace",
226                                         InfoType::IT_namespace);
227   TemplateMethod.Access = AccessSpecifier::AS_public;
228   TemplateMethod.IsMethod = true;
229   ExpectedRecordWithTemplateMethod.Children.Functions.emplace_back(
230       std::move(TemplateMethod));
231   CheckRecordInfo(&ExpectedRecordWithTemplateMethod, RecordWithTemplateMethod);
232 
233   RecordInfo *TemplatedRecord = InfoAsRecord(Infos[7].get());
234   RecordInfo ExpectedTemplatedRecord(EmptySID);
235   FunctionInfo SpecializedTemplateMethod;
236   SpecializedTemplateMethod.Name = "TemplateMethod";
237   SpecializedTemplateMethod.Parent =
238       Reference(EmptySID, "F", InfoType::IT_record);
239   SpecializedTemplateMethod.ReturnType = TypeInfo("void");
240   SpecializedTemplateMethod.Loc.emplace_back(0,
241                                              llvm::SmallString<16>{"test.cpp"});
242   SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "F",
243                                                    InfoType::IT_record);
244   SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace",
245                                                    InfoType::IT_namespace);
246   SpecializedTemplateMethod.Access = AccessSpecifier::AS_public;
247   SpecializedTemplateMethod.IsMethod = true;
248   ExpectedTemplatedRecord.Children.Functions.emplace_back(
249       std::move(SpecializedTemplateMethod));
250   CheckRecordInfo(&ExpectedTemplatedRecord, TemplatedRecord);
251 
252   RecordInfo *G = InfoAsRecord(Infos[8].get());
253   RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");
254   ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",
255                                    InfoType::IT_namespace);
256   ExpectedG.TagType = TagTypeKind::Struct;
257   ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
258   ExpectedG.IsTypeDef = true;
259   CheckRecordInfo(&ExpectedG, G);
260 }
261 
262 // Test serialization of enum declarations.
263 TEST(SerializeTest, emitEnumInfo) {
264   EmittedInfoList Infos;
265   ExtractInfosFromCode("enum E { X, Y }; enum class G { A, B };", 2,
266                        /*Public=*/false, Infos);
267 
268   NamespaceInfo *NamespaceWithEnum = InfoAsNamespace(Infos[0].get());
269   NamespaceInfo ExpectedNamespaceWithEnum(EmptySID);
270   EnumInfo E;
271   E.Name = "E";
272   E.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
273   E.Members.emplace_back("X", "0");
274   E.Members.emplace_back("Y", "1");
275   ExpectedNamespaceWithEnum.Children.Enums.emplace_back(std::move(E));
276   CheckNamespaceInfo(&ExpectedNamespaceWithEnum, NamespaceWithEnum);
277 
278   NamespaceInfo *NamespaceWithScopedEnum = InfoAsNamespace(Infos[1].get());
279   NamespaceInfo ExpectedNamespaceWithScopedEnum(EmptySID);
280   EnumInfo G;
281   G.Name = "G";
282   G.Scoped = true;
283   G.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
284   G.Members.emplace_back("A", "0");
285   G.Members.emplace_back("B", "1");
286   ExpectedNamespaceWithScopedEnum.Children.Enums.emplace_back(std::move(G));
287   CheckNamespaceInfo(&ExpectedNamespaceWithScopedEnum, NamespaceWithScopedEnum);
288 }
289 
290 TEST(SerializeTest, emitUndefinedRecordInfo) {
291   EmittedInfoList Infos;
292   ExtractInfosFromCode("class E;", 2, /*Public=*/false, Infos);
293 
294   RecordInfo *E = InfoAsRecord(Infos[0].get());
295   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
296   ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
297                                    InfoType::IT_namespace);
298   ExpectedE.TagType = TagTypeKind::Class;
299   ExpectedE.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"});
300   CheckRecordInfo(&ExpectedE, E);
301 }
302 
303 TEST(SerializeTest, emitRecordMemberInfo) {
304   EmittedInfoList Infos;
305   ExtractInfosFromCode("struct E { int I; };", 2, /*Public=*/false, Infos);
306 
307   RecordInfo *E = InfoAsRecord(Infos[0].get());
308   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
309   ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
310                                    InfoType::IT_namespace);
311   ExpectedE.TagType = TagTypeKind::Struct;
312   ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
313   ExpectedE.Members.emplace_back(TypeInfo("int"), "I",
314                                  AccessSpecifier::AS_public);
315   CheckRecordInfo(&ExpectedE, E);
316 }
317 
318 TEST(SerializeTest, emitInternalRecordInfo) {
319   EmittedInfoList Infos;
320   ExtractInfosFromCode("class E { class G {}; };", 4, /*Public=*/false, Infos);
321 
322   RecordInfo *E = InfoAsRecord(Infos[0].get());
323   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
324   ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
325                                    InfoType::IT_namespace);
326   ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
327   ExpectedE.TagType = TagTypeKind::Class;
328   CheckRecordInfo(&ExpectedE, E);
329 
330   RecordInfo *G = InfoAsRecord(Infos[2].get());
331   llvm::SmallString<128> ExpectedGPath("GlobalNamespace/E");
332   llvm::sys::path::native(ExpectedGPath);
333   RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/ExpectedGPath);
334   ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
335   ExpectedG.TagType = TagTypeKind::Class;
336   ExpectedG.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);
337   ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",
338                                    InfoType::IT_namespace);
339   CheckRecordInfo(&ExpectedG, G);
340 }
341 
342 TEST(SerializeTest, emitPublicAnonymousNamespaceInfo) {
343   EmittedInfoList Infos;
344   ExtractInfosFromCode("namespace { class A; }", 0, /*Public=*/true, Infos);
345 }
346 
347 TEST(SerializeTest, emitPublicFunctionInternalInfo) {
348   EmittedInfoList Infos;
349   ExtractInfosFromCode("int F() { class G {}; return 0; };", 1, /*Public=*/true,
350                        Infos);
351 
352   NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
353   NamespaceInfo ExpectedBWithFunction(EmptySID);
354   FunctionInfo F;
355   F.Name = "F";
356   F.ReturnType = TypeInfo("int");
357   F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
358   F.Access = AccessSpecifier::AS_none;
359   ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
360   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
361 }
362 
363 TEST(SerializeTest, emitInlinedFunctionInfo) {
364   EmittedInfoList Infos;
365   ExtractInfosFromCode("inline void F(int I) { };", 1, /*Public=*/true, Infos);
366 
367   NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
368   NamespaceInfo ExpectedBWithFunction(EmptySID);
369   FunctionInfo F;
370   F.Name = "F";
371   F.ReturnType = TypeInfo("void");
372   F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
373   F.Params.emplace_back(TypeInfo("int"), "I");
374   F.Access = AccessSpecifier::AS_none;
375   ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
376   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
377 }
378 
379 TEST(SerializeTest, emitInheritedRecordInfo) {
380   EmittedInfoList Infos;
381   ExtractInfosFromCode(R"raw(class F { protected: void set(int N); };
382 class G { public: int get() { return 1; } protected: int I; };
383 class E : public F, virtual private G {};
384 class H : private E {};
385 template <typename T>
386 class I {} ;
387 class J : public I<int> {} ;)raw",
388                        14, /*Public=*/false, Infos);
389 
390   RecordInfo *F = InfoAsRecord(Infos[0].get());
391   RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
392   ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace",
393                                    InfoType::IT_namespace, "");
394   ExpectedF.TagType = TagTypeKind::Class;
395   ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
396   CheckRecordInfo(&ExpectedF, F);
397 
398   RecordInfo *G = InfoAsRecord(Infos[3].get());
399   RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");
400   ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",
401                                    InfoType::IT_namespace);
402   ExpectedG.TagType = TagTypeKind::Class;
403   ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
404   ExpectedG.Members.emplace_back(TypeInfo("int"), "I",
405                                  AccessSpecifier::AS_protected);
406   CheckRecordInfo(&ExpectedG, G);
407 
408   RecordInfo *E = InfoAsRecord(Infos[6].get());
409   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
410   ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
411                                    InfoType::IT_namespace);
412   ExpectedE.Parents.emplace_back(EmptySID, /*Name=*/"F", InfoType::IT_record,
413                                  /*QualName=*/"", /*Path*=*/"GlobalNamespace");
414   ExpectedE.VirtualParents.emplace_back(EmptySID, /*Name=*/"G",
415                                         InfoType::IT_record, /*QualName=*/"G",
416                                         /*Path*=*/"GlobalNamespace");
417   ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"F",
418                                /*Path=*/"GlobalNamespace", false,
419                                AccessSpecifier::AS_public, true);
420   FunctionInfo FunctionSet;
421   FunctionSet.Name = "set";
422   FunctionSet.ReturnType = TypeInfo("void");
423   FunctionSet.Loc.emplace_back();
424   FunctionSet.Params.emplace_back(TypeInfo("int"), "N");
425   FunctionSet.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);
426   FunctionSet.Namespace.emplace_back(EmptySID, "GlobalNamespace",
427                                      InfoType::IT_namespace);
428   FunctionSet.Access = AccessSpecifier::AS_protected;
429   FunctionSet.IsMethod = true;
430   ExpectedE.Bases.back().Children.Functions.emplace_back(
431       std::move(FunctionSet));
432   ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"G",
433                                /*Path=*/"GlobalNamespace", true,
434                                AccessSpecifier::AS_private, true);
435   FunctionInfo FunctionGet;
436   FunctionGet.Name = "get";
437   FunctionGet.ReturnType = TypeInfo("int");
438   FunctionGet.DefLoc = Location();
439   FunctionGet.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record);
440   FunctionGet.Namespace.emplace_back(EmptySID, "GlobalNamespace",
441                                      InfoType::IT_namespace);
442   FunctionGet.Access = AccessSpecifier::AS_private;
443   FunctionGet.IsMethod = true;
444   ExpectedE.Bases.back().Children.Functions.emplace_back(
445       std::move(FunctionGet));
446   ExpectedE.Bases.back().Members.emplace_back(TypeInfo("int"), "I",
447                                               AccessSpecifier::AS_private);
448   ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
449   ExpectedE.TagType = TagTypeKind::Class;
450   CheckRecordInfo(&ExpectedE, E);
451 
452   RecordInfo *H = InfoAsRecord(Infos[8].get());
453   RecordInfo ExpectedH(EmptySID, /*Name=*/"H", /*Path=*/"GlobalNamespace");
454   ExpectedH.Namespace.emplace_back(EmptySID, "GlobalNamespace",
455                                    InfoType::IT_namespace);
456   ExpectedH.TagType = TagTypeKind::Class;
457   ExpectedH.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
458   ExpectedH.Parents.emplace_back(EmptySID, /*Name=*/"E", InfoType::IT_record,
459                                  /*QualName=*/"E", /*Path=*/"GlobalNamespace");
460   ExpectedH.VirtualParents.emplace_back(EmptySID, /*Name=*/"G",
461                                         InfoType::IT_record, /*QualName=*/"G",
462                                         /*Path=*/"GlobalNamespace");
463   ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"E",
464                                /*Path=*/"GlobalNamespace", false,
465                                AccessSpecifier::AS_private, true);
466   ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"F",
467                                /*Path=*/"GlobalNamespace", false,
468                                AccessSpecifier::AS_private, false);
469   FunctionInfo FunctionSetNew;
470   FunctionSetNew.Name = "set";
471   FunctionSetNew.ReturnType = TypeInfo("void");
472   FunctionSetNew.Loc.emplace_back();
473   FunctionSetNew.Params.emplace_back(TypeInfo("int"), "N");
474   FunctionSetNew.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);
475   FunctionSetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace",
476                                         InfoType::IT_namespace);
477   FunctionSetNew.Access = AccessSpecifier::AS_private;
478   FunctionSetNew.IsMethod = true;
479   ExpectedH.Bases.back().Children.Functions.emplace_back(
480       std::move(FunctionSetNew));
481   ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"G",
482                                /*Path=*/"GlobalNamespace", true,
483                                AccessSpecifier::AS_private, false);
484   FunctionInfo FunctionGetNew;
485   FunctionGetNew.Name = "get";
486   FunctionGetNew.ReturnType = TypeInfo("int");
487   FunctionGetNew.DefLoc = Location();
488   FunctionGetNew.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record);
489   FunctionGetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace",
490                                         InfoType::IT_namespace);
491   FunctionGetNew.Access = AccessSpecifier::AS_private;
492   FunctionGetNew.IsMethod = true;
493   ExpectedH.Bases.back().Children.Functions.emplace_back(
494       std::move(FunctionGetNew));
495   ExpectedH.Bases.back().Members.emplace_back(TypeInfo("int"), "I",
496                                               AccessSpecifier::AS_private);
497   CheckRecordInfo(&ExpectedH, H);
498 
499   RecordInfo *I = InfoAsRecord(Infos[10].get());
500   RecordInfo ExpectedI(EmptySID, /*Name=*/"I", /*Path=*/"GlobalNamespace");
501   ExpectedI.Namespace.emplace_back(EmptySID, "GlobalNamespace",
502                                    InfoType::IT_namespace);
503   ExpectedI.TagType = TagTypeKind::Class;
504   ExpectedI.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
505   CheckRecordInfo(&ExpectedI, I);
506 
507   RecordInfo *J = InfoAsRecord(Infos[12].get());
508   RecordInfo ExpectedJ(EmptySID, /*Name=*/"J", /*Path=*/"GlobalNamespace");
509   ExpectedJ.Namespace.emplace_back(EmptySID, "GlobalNamespace",
510                                    InfoType::IT_namespace);
511   ExpectedJ.Parents.emplace_back(EmptySID, /*Name=*/"I<int>",
512                                  InfoType::IT_record);
513   ExpectedJ.Bases.emplace_back(EmptySID, /*Name=*/"I<int>",
514                                /*Path=*/"GlobalNamespace", false,
515                                AccessSpecifier::AS_public, true);
516   ExpectedJ.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
517   ExpectedJ.TagType = TagTypeKind::Class;
518   CheckRecordInfo(&ExpectedJ, J);
519 }
520 
521 TEST(SerializeTest, emitModulePublicLFunctions) {
522   EmittedInfoList Infos;
523   std::vector<std::string> Args;
524   Args.push_back("-fmodules-ts");
525   ExtractInfosFromCodeWithArgs(R"raw(export module M;
526 int moduleFunction(int x, double d = 3.2 - 1.0);
527 static int staticModuleFunction(int x);
528 export double exportedModuleFunction(double y);)raw",
529                                2, /*Public=*/true, Infos, Args);
530 
531   NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
532   NamespaceInfo ExpectedBWithFunction(EmptySID);
533   FunctionInfo F;
534   F.Name = "moduleFunction";
535   F.ReturnType = TypeInfo("int");
536   F.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"});
537   F.Params.emplace_back(TypeInfo("int"), "x");
538   F.Params.emplace_back(TypeInfo("double"), "d");
539   F.Params.back().DefaultValue = "3.2 - 1.0";
540   F.Access = AccessSpecifier::AS_none;
541   ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
542   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
543 
544   NamespaceInfo *BWithExportedFunction = InfoAsNamespace(Infos[1].get());
545   NamespaceInfo ExpectedBWithExportedFunction(EmptySID);
546   FunctionInfo ExportedF;
547   ExportedF.Name = "exportedModuleFunction";
548   ExportedF.ReturnType =
549       TypeInfo(Reference(EmptySID, "double", InfoType::IT_default));
550   ExportedF.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"});
551   ExportedF.Params.emplace_back(TypeInfo("double"), "y");
552   ExportedF.Access = AccessSpecifier::AS_none;
553   ExpectedBWithExportedFunction.Children.Functions.emplace_back(
554       std::move(ExportedF));
555   CheckNamespaceInfo(&ExpectedBWithExportedFunction, BWithExportedFunction);
556 }
557 
558 // Test serialization of child records in namespaces and other records
559 TEST(SerializeTest, emitChildRecords) {
560   EmittedInfoList Infos;
561   ExtractInfosFromCode("class A { class B {}; }; namespace { class C {}; } ", 8,
562                        /*Public=*/false, Infos);
563 
564   NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
565   NamespaceInfo ExpectedParentA(EmptySID);
566   ExpectedParentA.Children.Records.emplace_back(
567       EmptySID, "A", InfoType::IT_record, "A", "GlobalNamespace");
568   CheckNamespaceInfo(&ExpectedParentA, ParentA);
569 
570   RecordInfo *ParentB = InfoAsRecord(Infos[3].get());
571   RecordInfo ExpectedParentB(EmptySID);
572   llvm::SmallString<128> ExpectedParentBPath("GlobalNamespace/A");
573   llvm::sys::path::native(ExpectedParentBPath);
574   ExpectedParentB.Children.Records.emplace_back(
575       EmptySID, "B", InfoType::IT_record, "A::B", ExpectedParentBPath);
576   CheckRecordInfo(&ExpectedParentB, ParentB);
577 
578   NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get());
579   NamespaceInfo ExpectedParentC(EmptySID);
580   ExpectedParentC.Children.Records.emplace_back(
581       EmptySID, "C", InfoType::IT_record, "C", "@nonymous_namespace");
582   CheckNamespaceInfo(&ExpectedParentC, ParentC);
583 }
584 
585 // Test serialization of child namespaces
586 TEST(SerializeTest, emitChildNamespaces) {
587   EmittedInfoList Infos;
588   ExtractInfosFromCode("namespace A { namespace B { } }", 4, /*Public=*/false,
589                        Infos);
590 
591   NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
592   NamespaceInfo ExpectedParentA(EmptySID);
593   ExpectedParentA.Children.Namespaces.emplace_back(EmptySID, "A",
594                                                    InfoType::IT_namespace);
595   CheckNamespaceInfo(&ExpectedParentA, ParentA);
596 
597   NamespaceInfo *ParentB = InfoAsNamespace(Infos[3].get());
598   NamespaceInfo ExpectedParentB(EmptySID);
599   ExpectedParentB.Children.Namespaces.emplace_back(
600       EmptySID, "B", InfoType::IT_namespace, "A::B", "A");
601   CheckNamespaceInfo(&ExpectedParentB, ParentB);
602 }
603 
604 TEST(SerializeTests, emitTypedefs) {
605   EmittedInfoList Infos;
606   ExtractInfosFromCode("typedef int MyInt; using MyDouble = double;", 2,
607                        /*Public=*/false, Infos);
608 
609   // First info will be the global namespace with the typedef in it.
610   NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get());
611   ASSERT_EQ(1u, GlobalNS1->Children.Typedefs.size());
612 
613   const TypedefInfo &FirstTD = GlobalNS1->Children.Typedefs[0];
614   EXPECT_EQ("MyInt", FirstTD.Name);
615   EXPECT_FALSE(FirstTD.IsUsing);
616   EXPECT_EQ("int", FirstTD.Underlying.Type.Name);
617 
618   // The second will be another global namespace with the using in it (the
619   // global namespace is duplicated because the items haven't been merged at the
620   // serialization phase of processing).
621   NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1].get());
622   ASSERT_EQ(1u, GlobalNS2->Children.Typedefs.size());
623 
624   // Second is the "using" typedef.
625   const TypedefInfo &SecondTD = GlobalNS2->Children.Typedefs[0];
626   EXPECT_EQ("MyDouble", SecondTD.Name);
627   EXPECT_TRUE(SecondTD.IsUsing);
628   EXPECT_EQ("double", SecondTD.Underlying.Type.Name);
629 }
630 
631 TEST(SerializeTests, emitFunctionTemplate) {
632   EmittedInfoList Infos;
633   // A template and a specialization.
634   ExtractInfosFromCode("template<typename T = int> bool GetFoo(T);\n"
635                        "template<> bool GetFoo<bool>(bool);",
636                        2,
637                        /*Public=*/false, Infos);
638 
639   // First info will be the global namespace.
640   NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get());
641   ASSERT_EQ(1u, GlobalNS1->Children.Functions.size());
642 
643   const FunctionInfo &Func1 = GlobalNS1->Children.Functions[0];
644   EXPECT_EQ("GetFoo", Func1.Name);
645   ASSERT_TRUE(Func1.Template);
646   EXPECT_FALSE(Func1.Template->Specialization); // Not a specialization.
647 
648   // Template parameter.
649   ASSERT_EQ(1u, Func1.Template->Params.size());
650   EXPECT_EQ("typename T = int", Func1.Template->Params[0].Contents);
651 
652   // The second will be another global namespace with the function in it (the
653   // global namespace is duplicated because the items haven't been merged at the
654   // serialization phase of processing).
655   NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1].get());
656   ASSERT_EQ(1u, GlobalNS2->Children.Functions.size());
657 
658   // This one is a template specialization.
659   const FunctionInfo &Func2 = GlobalNS2->Children.Functions[0];
660   EXPECT_EQ("GetFoo", Func2.Name);
661   ASSERT_TRUE(Func2.Template);
662   EXPECT_TRUE(Func2.Template->Params.empty()); // No template params.
663   ASSERT_TRUE(Func2.Template->Specialization);
664 
665   // Specialization values.
666   ASSERT_EQ(1u, Func2.Template->Specialization->Params.size());
667   EXPECT_EQ("bool", Func2.Template->Specialization->Params[0].Contents);
668   EXPECT_EQ(Func1.USR, Func2.Template->Specialization->SpecializationOf);
669 
670   EXPECT_EQ("bool", Func2.ReturnType.Type.Name);
671 }
672 
673 TEST(SerializeTests, emitClassTemplate) {
674   EmittedInfoList Infos;
675   // This will generate 2x the number of infos: each Record will be followed by
676   // a copy of the global namespace containing it (this test checks the data
677   // pre-merge).
678   ExtractInfosFromCode(
679       "template<int I> class MyTemplate { int i[I]; };\n"
680       "template<> class MyTemplate<0> {};\n"
681       "template<typename T, int U = 1> class OtherTemplate {};\n"
682       "template<int U> class OtherTemplate<MyTemplate<0>, U> {};",
683       8,
684       /*Public=*/false, Infos);
685 
686   // First record.
687   const RecordInfo *Rec1 = InfoAsRecord(Infos[0].get());
688   EXPECT_EQ("MyTemplate", Rec1->Name);
689   ASSERT_TRUE(Rec1->Template);
690   EXPECT_FALSE(Rec1->Template->Specialization); // Not a specialization.
691 
692   // First record template parameter.
693   ASSERT_EQ(1u, Rec1->Template->Params.size());
694   EXPECT_EQ("int I", Rec1->Template->Params[0].Contents);
695 
696   // Second record.
697   const RecordInfo *Rec2 = InfoAsRecord(Infos[2].get());
698   EXPECT_EQ("MyTemplate", Rec2->Name);
699   ASSERT_TRUE(Rec2->Template);
700   EXPECT_TRUE(Rec2->Template->Params.empty()); // No template params.
701   ASSERT_TRUE(Rec2->Template->Specialization);
702 
703   // Second record specialization values.
704   ASSERT_EQ(1u, Rec2->Template->Specialization->Params.size());
705   EXPECT_EQ("0", Rec2->Template->Specialization->Params[0].Contents);
706   EXPECT_EQ(Rec1->USR, Rec2->Template->Specialization->SpecializationOf);
707 
708   // Third record.
709   const RecordInfo *Rec3 = InfoAsRecord(Infos[4].get());
710   EXPECT_EQ("OtherTemplate", Rec3->Name);
711   ASSERT_TRUE(Rec3->Template);
712 
713   // Third record template parameters.
714   ASSERT_EQ(2u, Rec3->Template->Params.size());
715   EXPECT_EQ("typename T", Rec3->Template->Params[0].Contents);
716   EXPECT_EQ("int U = 1", Rec3->Template->Params[1].Contents);
717 
718   // Fourth record.
719   const RecordInfo *Rec4 = InfoAsRecord(Infos[6].get());
720   EXPECT_EQ("OtherTemplate", Rec3->Name);
721   ASSERT_TRUE(Rec4->Template);
722   ASSERT_TRUE(Rec4->Template->Specialization);
723 
724   // Fourth record template + specialization parameters.
725   ASSERT_EQ(1u, Rec4->Template->Params.size());
726   EXPECT_EQ("int U", Rec4->Template->Params[0].Contents);
727   ASSERT_EQ(2u, Rec4->Template->Specialization->Params.size());
728   EXPECT_EQ("MyTemplate<0>",
729             Rec4->Template->Specialization->Params[0].Contents);
730   EXPECT_EQ("U", Rec4->Template->Specialization->Params[1].Contents);
731 }
732 
733 } // namespace doc
734 } // end namespace clang
735