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
16namespace clang {
17namespace doc {
18
19class 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(Context: D->getASTContext(), PP: nullptr, D);
30 }
31 return nullptr;
32 }
33
34public:
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>(Val: 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
68void 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
77void 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.
90CommentInfo 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.
108TEST(SerializeTest, emitNamespaceInfo) {
109 EmittedInfoList Infos;
110 ExtractInfosFromCode(Code: "namespace A { namespace B { void f() {} } }", NumExpectedInfos: 5,
111 /*Public=*/false, EmittedInfos&: Infos);
112
113 NamespaceInfo *A = InfoAsNamespace(I: Infos[0].get());
114 NamespaceInfo ExpectedA(EmptySID, "A");
115 CheckNamespaceInfo(Expected: &ExpectedA, Actual: A);
116
117 NamespaceInfo *B = InfoAsNamespace(I: Infos[2].get());
118 NamespaceInfo ExpectedB(EmptySID, /*Name=*/"B", /*Path=*/"A");
119 ExpectedB.Namespace.emplace_back(Args: EmptySID, Args: "A", Args: InfoType::IT_namespace);
120 CheckNamespaceInfo(Expected: &ExpectedB, Actual: B);
121
122 NamespaceInfo *BWithFunction = InfoAsNamespace(I: 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(Args: EmptySID, Args: "B", Args: InfoType::IT_namespace);
129 F.Namespace.emplace_back(Args: EmptySID, Args: "A", Args: InfoType::IT_namespace);
130 F.Access = AccessSpecifier::AS_none;
131 ExpectedBWithFunction.Children.Functions.emplace_back(args: std::move(F));
132 CheckNamespaceInfo(Expected: &ExpectedBWithFunction, Actual: BWithFunction);
133}
134
135TEST(SerializeTest, emitAnonymousNamespaceInfo) {
136 EmittedInfoList Infos;
137 ExtractInfosFromCode(Code: "namespace { }", NumExpectedInfos: 2, /*Public=*/false, EmittedInfos&: Infos);
138
139 NamespaceInfo *A = InfoAsNamespace(I: Infos[0].get());
140 NamespaceInfo ExpectedA(EmptySID);
141 ExpectedA.Name = "@nonymous_namespace";
142 CheckNamespaceInfo(Expected: &ExpectedA, Actual: A);
143}
144
145// Test serialization of record declarations.
146TEST(SerializeTest, emitRecordInfo) {
147 EmittedInfoList Infos;
148 ExtractInfosFromCode(Code: R"raw(class E {
149public:
150 E() {}
151
152 // Some docs.
153 int value;
154protected:
155 void ProtectedMethod();
156};
157template <typename T>
158struct F {
159 void TemplateMethod();
160};
161template <>
162void F<int>::TemplateMethod();
163typedef struct {} G;)raw",
164 NumExpectedInfos: 10, /*Public=*/false, EmittedInfos&: Infos);
165
166 RecordInfo *E = InfoAsRecord(I: Infos[0].get());
167 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
168 ExpectedE.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
169 Args: InfoType::IT_namespace);
170 ExpectedE.TagType = TagTypeKind::Class;
171 ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
172 ExpectedE.Members.emplace_back(Args: TypeInfo("int"), Args: "value",
173 Args: 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(Expected: &ExpectedE, Actual: E);
177
178 RecordInfo *RecordWithEConstructor = InfoAsRecord(I: 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(Args: EmptySID, Args: "E", Args: InfoType::IT_record);
186 EConstructor.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
187 Args: InfoType::IT_namespace);
188 EConstructor.Access = AccessSpecifier::AS_public;
189 EConstructor.IsMethod = true;
190 ExpectedRecordWithEConstructor.Children.Functions.emplace_back(
191 args: std::move(EConstructor));
192 CheckRecordInfo(Expected: &ExpectedRecordWithEConstructor, Actual: RecordWithEConstructor);
193
194 RecordInfo *RecordWithMethod = InfoAsRecord(I: 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(Args: 0, Args: llvm::SmallString<16>{"test.cpp"});
201 Method.Namespace.emplace_back(Args: EmptySID, Args: "E", Args: InfoType::IT_record);
202 Method.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
203 Args: InfoType::IT_namespace);
204 Method.Access = AccessSpecifier::AS_protected;
205 Method.IsMethod = true;
206 ExpectedRecordWithMethod.Children.Functions.emplace_back(args: std::move(Method));
207 CheckRecordInfo(Expected: &ExpectedRecordWithMethod, Actual: RecordWithMethod);
208
209 RecordInfo *F = InfoAsRecord(I: Infos[4].get());
210 RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
211 ExpectedF.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
212 Args: InfoType::IT_namespace);
213 ExpectedF.TagType = TagTypeKind::Struct;
214 ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
215 CheckRecordInfo(Expected: &ExpectedF, Actual: F);
216
217 RecordInfo *RecordWithTemplateMethod = InfoAsRecord(I: 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(Args: 0, Args: llvm::SmallString<16>{"test.cpp"});
224 TemplateMethod.Namespace.emplace_back(Args: EmptySID, Args: "F", Args: InfoType::IT_record);
225 TemplateMethod.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
226 Args: InfoType::IT_namespace);
227 TemplateMethod.Access = AccessSpecifier::AS_public;
228 TemplateMethod.IsMethod = true;
229 ExpectedRecordWithTemplateMethod.Children.Functions.emplace_back(
230 args: std::move(TemplateMethod));
231 CheckRecordInfo(Expected: &ExpectedRecordWithTemplateMethod, Actual: RecordWithTemplateMethod);
232
233 RecordInfo *TemplatedRecord = InfoAsRecord(I: 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(Args: 0,
241 Args: llvm::SmallString<16>{"test.cpp"});
242 SpecializedTemplateMethod.Namespace.emplace_back(Args: EmptySID, Args: "F",
243 Args: InfoType::IT_record);
244 SpecializedTemplateMethod.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
245 Args: InfoType::IT_namespace);
246 SpecializedTemplateMethod.Access = AccessSpecifier::AS_public;
247 SpecializedTemplateMethod.IsMethod = true;
248 ExpectedTemplatedRecord.Children.Functions.emplace_back(
249 args: std::move(SpecializedTemplateMethod));
250 CheckRecordInfo(Expected: &ExpectedTemplatedRecord, Actual: TemplatedRecord);
251
252 RecordInfo *G = InfoAsRecord(I: Infos[8].get());
253 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");
254 ExpectedG.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
255 Args: InfoType::IT_namespace);
256 ExpectedG.TagType = TagTypeKind::Struct;
257 ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
258 ExpectedG.IsTypeDef = true;
259 CheckRecordInfo(Expected: &ExpectedG, Actual: G);
260}
261
262// Test serialization of enum declarations.
263TEST(SerializeTest, emitEnumInfo) {
264 EmittedInfoList Infos;
265 ExtractInfosFromCode(Code: "enum E { X, Y }; enum class G { A, B };", NumExpectedInfos: 2,
266 /*Public=*/false, EmittedInfos&: Infos);
267
268 NamespaceInfo *NamespaceWithEnum = InfoAsNamespace(I: 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(Args: "X", Args: "0");
274 E.Members.emplace_back(Args: "Y", Args: "1");
275 ExpectedNamespaceWithEnum.Children.Enums.emplace_back(args: std::move(E));
276 CheckNamespaceInfo(Expected: &ExpectedNamespaceWithEnum, Actual: NamespaceWithEnum);
277
278 NamespaceInfo *NamespaceWithScopedEnum = InfoAsNamespace(I: 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(Args: "A", Args: "0");
285 G.Members.emplace_back(Args: "B", Args: "1");
286 ExpectedNamespaceWithScopedEnum.Children.Enums.emplace_back(args: std::move(G));
287 CheckNamespaceInfo(Expected: &ExpectedNamespaceWithScopedEnum, Actual: NamespaceWithScopedEnum);
288}
289
290TEST(SerializeTest, emitUndefinedRecordInfo) {
291 EmittedInfoList Infos;
292 ExtractInfosFromCode(Code: "class E;", NumExpectedInfos: 2, /*Public=*/false, EmittedInfos&: Infos);
293
294 RecordInfo *E = InfoAsRecord(I: Infos[0].get());
295 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
296 ExpectedE.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
297 Args: InfoType::IT_namespace);
298 ExpectedE.TagType = TagTypeKind::Class;
299 ExpectedE.Loc.emplace_back(Args: 0, Args: llvm::SmallString<16>{"test.cpp"});
300 CheckRecordInfo(Expected: &ExpectedE, Actual: E);
301}
302
303TEST(SerializeTest, emitRecordMemberInfo) {
304 EmittedInfoList Infos;
305 ExtractInfosFromCode(Code: "struct E { int I; };", NumExpectedInfos: 2, /*Public=*/false, EmittedInfos&: Infos);
306
307 RecordInfo *E = InfoAsRecord(I: Infos[0].get());
308 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
309 ExpectedE.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
310 Args: InfoType::IT_namespace);
311 ExpectedE.TagType = TagTypeKind::Struct;
312 ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
313 ExpectedE.Members.emplace_back(Args: TypeInfo("int"), Args: "I",
314 Args: AccessSpecifier::AS_public);
315 CheckRecordInfo(Expected: &ExpectedE, Actual: E);
316}
317
318TEST(SerializeTest, emitInternalRecordInfo) {
319 EmittedInfoList Infos;
320 ExtractInfosFromCode(Code: "class E { class G {}; };", NumExpectedInfos: 4, /*Public=*/false, EmittedInfos&: Infos);
321
322 RecordInfo *E = InfoAsRecord(I: Infos[0].get());
323 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
324 ExpectedE.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
325 Args: InfoType::IT_namespace);
326 ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
327 ExpectedE.TagType = TagTypeKind::Class;
328 CheckRecordInfo(Expected: &ExpectedE, Actual: E);
329
330 RecordInfo *G = InfoAsRecord(I: Infos[2].get());
331 llvm::SmallString<128> ExpectedGPath("GlobalNamespace/E");
332 llvm::sys::path::native(path&: 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(Args: EmptySID, Args: "E", Args: InfoType::IT_record);
337 ExpectedG.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
338 Args: InfoType::IT_namespace);
339 CheckRecordInfo(Expected: &ExpectedG, Actual: G);
340}
341
342TEST(SerializeTest, emitPublicAnonymousNamespaceInfo) {
343 EmittedInfoList Infos;
344 ExtractInfosFromCode(Code: "namespace { class A; }", NumExpectedInfos: 0, /*Public=*/true, EmittedInfos&: Infos);
345}
346
347TEST(SerializeTest, emitPublicFunctionInternalInfo) {
348 EmittedInfoList Infos;
349 ExtractInfosFromCode(Code: "int F() { class G {}; return 0; };", NumExpectedInfos: 1, /*Public=*/true,
350 EmittedInfos&: Infos);
351
352 NamespaceInfo *BWithFunction = InfoAsNamespace(I: 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(args: std::move(F));
360 CheckNamespaceInfo(Expected: &ExpectedBWithFunction, Actual: BWithFunction);
361}
362
363TEST(SerializeTest, emitInlinedFunctionInfo) {
364 EmittedInfoList Infos;
365 ExtractInfosFromCode(Code: "inline void F(int I) { };", NumExpectedInfos: 1, /*Public=*/true, EmittedInfos&: Infos);
366
367 NamespaceInfo *BWithFunction = InfoAsNamespace(I: 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(Args: TypeInfo("int"), Args: "I");
374 F.Access = AccessSpecifier::AS_none;
375 ExpectedBWithFunction.Children.Functions.emplace_back(args: std::move(F));
376 CheckNamespaceInfo(Expected: &ExpectedBWithFunction, Actual: BWithFunction);
377}
378
379TEST(SerializeTest, emitInheritedRecordInfo) {
380 EmittedInfoList Infos;
381 ExtractInfosFromCode(Code: R"raw(class F { protected: void set(int N); };
382class G { public: int get() { return 1; } protected: int I; };
383class E : public F, virtual private G {};
384class H : private E {};
385template <typename T>
386class I {} ;
387class J : public I<int> {} ;)raw",
388 NumExpectedInfos: 14, /*Public=*/false, EmittedInfos&: Infos);
389
390 RecordInfo *F = InfoAsRecord(I: Infos[0].get());
391 RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
392 ExpectedF.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
393 Args: InfoType::IT_namespace, Args: "");
394 ExpectedF.TagType = TagTypeKind::Class;
395 ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
396 CheckRecordInfo(Expected: &ExpectedF, Actual: F);
397
398 RecordInfo *G = InfoAsRecord(I: Infos[3].get());
399 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");
400 ExpectedG.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
401 Args: InfoType::IT_namespace);
402 ExpectedG.TagType = TagTypeKind::Class;
403 ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
404 ExpectedG.Members.emplace_back(Args: TypeInfo("int"), Args: "I",
405 Args: AccessSpecifier::AS_protected);
406 CheckRecordInfo(Expected: &ExpectedG, Actual: G);
407
408 RecordInfo *E = InfoAsRecord(I: Infos[6].get());
409 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
410 ExpectedE.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
411 Args: InfoType::IT_namespace);
412 ExpectedE.Parents.emplace_back(Args: EmptySID, /*Name=*/Args: "F", Args: InfoType::IT_record,
413 /*QualName=*/Args: "", /*Path*=*/Args: "GlobalNamespace");
414 ExpectedE.VirtualParents.emplace_back(Args: EmptySID, /*Name=*/Args: "G",
415 Args: InfoType::IT_record, /*QualName=*/Args: "G",
416 /*Path*=*/Args: "GlobalNamespace");
417 ExpectedE.Bases.emplace_back(args: EmptySID, /*Name=*/args: "F",
418 /*Path=*/args: "GlobalNamespace", args: false,
419 args: AccessSpecifier::AS_public, args: true);
420 FunctionInfo FunctionSet;
421 FunctionSet.Name = "set";
422 FunctionSet.ReturnType = TypeInfo("void");
423 FunctionSet.Loc.emplace_back();
424 FunctionSet.Params.emplace_back(Args: TypeInfo("int"), Args: "N");
425 FunctionSet.Namespace.emplace_back(Args: EmptySID, Args: "F", Args: InfoType::IT_record);
426 FunctionSet.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
427 Args: InfoType::IT_namespace);
428 FunctionSet.Access = AccessSpecifier::AS_protected;
429 FunctionSet.IsMethod = true;
430 ExpectedE.Bases.back().Children.Functions.emplace_back(
431 args: std::move(FunctionSet));
432 ExpectedE.Bases.emplace_back(args: EmptySID, /*Name=*/args: "G",
433 /*Path=*/args: "GlobalNamespace", args: true,
434 args: AccessSpecifier::AS_private, args: true);
435 FunctionInfo FunctionGet;
436 FunctionGet.Name = "get";
437 FunctionGet.ReturnType = TypeInfo("int");
438 FunctionGet.DefLoc = Location();
439 FunctionGet.Namespace.emplace_back(Args: EmptySID, Args: "G", Args: InfoType::IT_record);
440 FunctionGet.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
441 Args: InfoType::IT_namespace);
442 FunctionGet.Access = AccessSpecifier::AS_private;
443 FunctionGet.IsMethod = true;
444 ExpectedE.Bases.back().Children.Functions.emplace_back(
445 args: std::move(FunctionGet));
446 ExpectedE.Bases.back().Members.emplace_back(Args: TypeInfo("int"), Args: "I",
447 Args: AccessSpecifier::AS_private);
448 ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
449 ExpectedE.TagType = TagTypeKind::Class;
450 CheckRecordInfo(Expected: &ExpectedE, Actual: E);
451
452 RecordInfo *H = InfoAsRecord(I: Infos[8].get());
453 RecordInfo ExpectedH(EmptySID, /*Name=*/"H", /*Path=*/"GlobalNamespace");
454 ExpectedH.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
455 Args: InfoType::IT_namespace);
456 ExpectedH.TagType = TagTypeKind::Class;
457 ExpectedH.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
458 ExpectedH.Parents.emplace_back(Args: EmptySID, /*Name=*/Args: "E", Args: InfoType::IT_record,
459 /*QualName=*/Args: "E", /*Path=*/Args: "GlobalNamespace");
460 ExpectedH.VirtualParents.emplace_back(Args: EmptySID, /*Name=*/Args: "G",
461 Args: InfoType::IT_record, /*QualName=*/Args: "G",
462 /*Path=*/Args: "GlobalNamespace");
463 ExpectedH.Bases.emplace_back(args: EmptySID, /*Name=*/args: "E",
464 /*Path=*/args: "GlobalNamespace", args: false,
465 args: AccessSpecifier::AS_private, args: true);
466 ExpectedH.Bases.emplace_back(args: EmptySID, /*Name=*/args: "F",
467 /*Path=*/args: "GlobalNamespace", args: false,
468 args: AccessSpecifier::AS_private, args: false);
469 FunctionInfo FunctionSetNew;
470 FunctionSetNew.Name = "set";
471 FunctionSetNew.ReturnType = TypeInfo("void");
472 FunctionSetNew.Loc.emplace_back();
473 FunctionSetNew.Params.emplace_back(Args: TypeInfo("int"), Args: "N");
474 FunctionSetNew.Namespace.emplace_back(Args: EmptySID, Args: "F", Args: InfoType::IT_record);
475 FunctionSetNew.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
476 Args: InfoType::IT_namespace);
477 FunctionSetNew.Access = AccessSpecifier::AS_private;
478 FunctionSetNew.IsMethod = true;
479 ExpectedH.Bases.back().Children.Functions.emplace_back(
480 args: std::move(FunctionSetNew));
481 ExpectedH.Bases.emplace_back(args: EmptySID, /*Name=*/args: "G",
482 /*Path=*/args: "GlobalNamespace", args: true,
483 args: AccessSpecifier::AS_private, args: false);
484 FunctionInfo FunctionGetNew;
485 FunctionGetNew.Name = "get";
486 FunctionGetNew.ReturnType = TypeInfo("int");
487 FunctionGetNew.DefLoc = Location();
488 FunctionGetNew.Namespace.emplace_back(Args: EmptySID, Args: "G", Args: InfoType::IT_record);
489 FunctionGetNew.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
490 Args: InfoType::IT_namespace);
491 FunctionGetNew.Access = AccessSpecifier::AS_private;
492 FunctionGetNew.IsMethod = true;
493 ExpectedH.Bases.back().Children.Functions.emplace_back(
494 args: std::move(FunctionGetNew));
495 ExpectedH.Bases.back().Members.emplace_back(Args: TypeInfo("int"), Args: "I",
496 Args: AccessSpecifier::AS_private);
497 CheckRecordInfo(Expected: &ExpectedH, Actual: H);
498
499 RecordInfo *I = InfoAsRecord(I: Infos[10].get());
500 RecordInfo ExpectedI(EmptySID, /*Name=*/"I", /*Path=*/"GlobalNamespace");
501 ExpectedI.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
502 Args: InfoType::IT_namespace);
503 ExpectedI.TagType = TagTypeKind::Class;
504 ExpectedI.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
505 CheckRecordInfo(Expected: &ExpectedI, Actual: I);
506
507 RecordInfo *J = InfoAsRecord(I: Infos[12].get());
508 RecordInfo ExpectedJ(EmptySID, /*Name=*/"J", /*Path=*/"GlobalNamespace");
509 ExpectedJ.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
510 Args: InfoType::IT_namespace);
511 ExpectedJ.Parents.emplace_back(Args: EmptySID, /*Name=*/Args: "I<int>",
512 Args: InfoType::IT_record);
513 ExpectedJ.Bases.emplace_back(args: EmptySID, /*Name=*/args: "I<int>",
514 /*Path=*/args: "GlobalNamespace", args: false,
515 args: AccessSpecifier::AS_public, args: true);
516 ExpectedJ.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
517 ExpectedJ.TagType = TagTypeKind::Class;
518 CheckRecordInfo(Expected: &ExpectedJ, Actual: J);
519}
520
521TEST(SerializeTest, emitModulePublicLFunctions) {
522 EmittedInfoList Infos;
523 std::vector<std::string> Args;
524 Args.push_back(x: "-fmodules-ts");
525 ExtractInfosFromCodeWithArgs(Code: R"raw(export module M;
526int moduleFunction(int x, double d = 3.2 - 1.0);
527static int staticModuleFunction(int x);
528export double exportedModuleFunction(double y);)raw",
529 NumExpectedInfos: 2, /*Public=*/true, EmittedInfos&: Infos, Args);
530
531 NamespaceInfo *BWithFunction = InfoAsNamespace(I: Infos[0].get());
532 NamespaceInfo ExpectedBWithFunction(EmptySID);
533 FunctionInfo F;
534 F.Name = "moduleFunction";
535 F.ReturnType = TypeInfo("int");
536 F.Loc.emplace_back(Args: 0, Args: llvm::SmallString<16>{"test.cpp"});
537 F.Params.emplace_back(Args: TypeInfo("int"), Args: "x");
538 F.Params.emplace_back(Args: TypeInfo("double"), Args: "d");
539 F.Params.back().DefaultValue = "3.2 - 1.0";
540 F.Access = AccessSpecifier::AS_none;
541 ExpectedBWithFunction.Children.Functions.emplace_back(args: std::move(F));
542 CheckNamespaceInfo(Expected: &ExpectedBWithFunction, Actual: BWithFunction);
543
544 NamespaceInfo *BWithExportedFunction = InfoAsNamespace(I: 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(Args: 0, Args: llvm::SmallString<16>{"test.cpp"});
551 ExportedF.Params.emplace_back(Args: TypeInfo("double"), Args: "y");
552 ExportedF.Access = AccessSpecifier::AS_none;
553 ExpectedBWithExportedFunction.Children.Functions.emplace_back(
554 args: std::move(ExportedF));
555 CheckNamespaceInfo(Expected: &ExpectedBWithExportedFunction, Actual: BWithExportedFunction);
556}
557
558// Test serialization of child records in namespaces and other records
559TEST(SerializeTest, emitChildRecords) {
560 EmittedInfoList Infos;
561 ExtractInfosFromCode(Code: "class A { class B {}; }; namespace { class C {}; } ", NumExpectedInfos: 8,
562 /*Public=*/false, EmittedInfos&: Infos);
563
564 NamespaceInfo *ParentA = InfoAsNamespace(I: Infos[1].get());
565 NamespaceInfo ExpectedParentA(EmptySID);
566 ExpectedParentA.Children.Records.emplace_back(
567 args: EmptySID, args: "A", args: InfoType::IT_record, args: "A", args: "GlobalNamespace");
568 CheckNamespaceInfo(Expected: &ExpectedParentA, Actual: ParentA);
569
570 RecordInfo *ParentB = InfoAsRecord(I: Infos[3].get());
571 RecordInfo ExpectedParentB(EmptySID);
572 llvm::SmallString<128> ExpectedParentBPath("GlobalNamespace/A");
573 llvm::sys::path::native(path&: ExpectedParentBPath);
574 ExpectedParentB.Children.Records.emplace_back(
575 args: EmptySID, args: "B", args: InfoType::IT_record, args: "A::B", args&: ExpectedParentBPath);
576 CheckRecordInfo(Expected: &ExpectedParentB, Actual: ParentB);
577
578 NamespaceInfo *ParentC = InfoAsNamespace(I: Infos[7].get());
579 NamespaceInfo ExpectedParentC(EmptySID);
580 ExpectedParentC.Children.Records.emplace_back(
581 args: EmptySID, args: "C", args: InfoType::IT_record, args: "C", args: "@nonymous_namespace");
582 CheckNamespaceInfo(Expected: &ExpectedParentC, Actual: ParentC);
583}
584
585// Test serialization of child namespaces
586TEST(SerializeTest, emitChildNamespaces) {
587 EmittedInfoList Infos;
588 ExtractInfosFromCode(Code: "namespace A { namespace B { } }", NumExpectedInfos: 4, /*Public=*/false,
589 EmittedInfos&: Infos);
590
591 NamespaceInfo *ParentA = InfoAsNamespace(I: Infos[1].get());
592 NamespaceInfo ExpectedParentA(EmptySID);
593 ExpectedParentA.Children.Namespaces.emplace_back(args: EmptySID, args: "A",
594 args: InfoType::IT_namespace);
595 CheckNamespaceInfo(Expected: &ExpectedParentA, Actual: ParentA);
596
597 NamespaceInfo *ParentB = InfoAsNamespace(I: Infos[3].get());
598 NamespaceInfo ExpectedParentB(EmptySID);
599 ExpectedParentB.Children.Namespaces.emplace_back(
600 args: EmptySID, args: "B", args: InfoType::IT_namespace, args: "A::B", args: "A");
601 CheckNamespaceInfo(Expected: &ExpectedParentB, Actual: ParentB);
602}
603
604TEST(SerializeTests, emitTypedefs) {
605 EmittedInfoList Infos;
606 ExtractInfosFromCode(Code: "typedef int MyInt; using MyDouble = double;", NumExpectedInfos: 2,
607 /*Public=*/false, EmittedInfos&: Infos);
608
609 // First info will be the global namespace with the typedef in it.
610 NamespaceInfo *GlobalNS1 = InfoAsNamespace(I: 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(I: 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
631TEST(SerializeTests, emitFunctionTemplate) {
632 EmittedInfoList Infos;
633 // A template and a specialization.
634 ExtractInfosFromCode(Code: "template<typename T = int> void GetFoo(T);\n"
635 "template<> void GetFoo<bool>(bool);",
636 NumExpectedInfos: 2,
637 /*Public=*/false, EmittedInfos&: Infos);
638
639 // First info will be the global namespace.
640 NamespaceInfo *GlobalNS1 = InfoAsNamespace(I: 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(I: 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
671TEST(SerializeTests, emitClassTemplate) {
672 EmittedInfoList Infos;
673 // This will generate 2x the number of infos: each Record will be followed by
674 // a copy of the global namespace containing it (this test checks the data
675 // pre-merge).
676 ExtractInfosFromCode(
677 Code: "template<int I> class MyTemplate { int i[I]; };\n"
678 "template<> class MyTemplate<0> {};\n"
679 "template<typename T, int U = 1> class OtherTemplate {};\n"
680 "template<int U> class OtherTemplate<MyTemplate<0>, U> {};",
681 NumExpectedInfos: 8,
682 /*Public=*/false, EmittedInfos&: Infos);
683
684 // First record.
685 const RecordInfo *Rec1 = InfoAsRecord(I: Infos[0].get());
686 EXPECT_EQ("MyTemplate", Rec1->Name);
687 ASSERT_TRUE(Rec1->Template);
688 EXPECT_FALSE(Rec1->Template->Specialization); // Not a specialization.
689
690 // First record template parameter.
691 ASSERT_EQ(1u, Rec1->Template->Params.size());
692 EXPECT_EQ("int I", Rec1->Template->Params[0].Contents);
693
694 // Second record.
695 const RecordInfo *Rec2 = InfoAsRecord(I: Infos[2].get());
696 EXPECT_EQ("MyTemplate", Rec2->Name);
697 ASSERT_TRUE(Rec2->Template);
698 EXPECT_TRUE(Rec2->Template->Params.empty()); // No template params.
699 ASSERT_TRUE(Rec2->Template->Specialization);
700
701 // Second record specialization values.
702 ASSERT_EQ(1u, Rec2->Template->Specialization->Params.size());
703 EXPECT_EQ("0", Rec2->Template->Specialization->Params[0].Contents);
704 EXPECT_EQ(Rec1->USR, Rec2->Template->Specialization->SpecializationOf);
705
706 // Third record.
707 const RecordInfo *Rec3 = InfoAsRecord(I: Infos[4].get());
708 EXPECT_EQ("OtherTemplate", Rec3->Name);
709 ASSERT_TRUE(Rec3->Template);
710
711 // Third record template parameters.
712 ASSERT_EQ(2u, Rec3->Template->Params.size());
713 EXPECT_EQ("typename T", Rec3->Template->Params[0].Contents);
714 EXPECT_EQ("int U = 1", Rec3->Template->Params[1].Contents);
715
716 // Fourth record.
717 const RecordInfo *Rec4 = InfoAsRecord(I: Infos[6].get());
718 EXPECT_EQ("OtherTemplate", Rec3->Name);
719 ASSERT_TRUE(Rec4->Template);
720 ASSERT_TRUE(Rec4->Template->Specialization);
721
722 // Fourth record template + specialization parameters.
723 ASSERT_EQ(1u, Rec4->Template->Params.size());
724 EXPECT_EQ("int U", Rec4->Template->Params[0].Contents);
725 ASSERT_EQ(2u, Rec4->Template->Specialization->Params.size());
726 EXPECT_EQ("MyTemplate<0>",
727 Rec4->Template->Specialization->Params[0].Contents);
728 EXPECT_EQ("U", Rec4->Template->Specialization->Params[1].Contents);
729}
730
731} // namespace doc
732} // end namespace clang
733

source code of clang-tools-extra/unittests/clang-doc/SerializeTest.cpp