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 Location Loc(0, 0, "test.cpp");
40 auto [Child, Parent] = serialize::emitInfo(D, getComment(D), Loc, Public);
41 if (Child)
42 EmittedInfos.emplace_back(std::move(Child));
43 if (Parent)
44 EmittedInfos.emplace_back(std::move(Parent));
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, 0, "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, 0, "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, 0, "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: 0, Args: "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, 0, "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: 0, Args: "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, Args: 0, Args: "test.cpp");
241 SpecializedTemplateMethod.Namespace.emplace_back(Args: EmptySID, Args: "F",
242 Args: InfoType::IT_record);
243 SpecializedTemplateMethod.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
244 Args: InfoType::IT_namespace);
245 SpecializedTemplateMethod.Access = AccessSpecifier::AS_public;
246 SpecializedTemplateMethod.IsMethod = true;
247 ExpectedTemplatedRecord.Children.Functions.emplace_back(
248 args: std::move(SpecializedTemplateMethod));
249 CheckRecordInfo(Expected: &ExpectedTemplatedRecord, Actual: TemplatedRecord);
250
251 RecordInfo *G = InfoAsRecord(I: Infos[8].get());
252 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");
253 ExpectedG.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
254 Args: InfoType::IT_namespace);
255 ExpectedG.TagType = TagTypeKind::Struct;
256 ExpectedG.DefLoc = Location(0, 0, "test.cpp");
257 ExpectedG.IsTypeDef = true;
258 CheckRecordInfo(Expected: &ExpectedG, Actual: G);
259}
260
261// Test serialization of enum declarations.
262TEST(SerializeTest, emitEnumInfo) {
263 EmittedInfoList Infos;
264 ExtractInfosFromCode(Code: "enum E { X, Y }; enum class G { A, B };", NumExpectedInfos: 2,
265 /*Public=*/false, EmittedInfos&: Infos);
266
267 NamespaceInfo *NamespaceWithEnum = InfoAsNamespace(I: Infos[0].get());
268 NamespaceInfo ExpectedNamespaceWithEnum(EmptySID);
269 EnumInfo E;
270 E.Name = "E";
271 E.DefLoc = Location(0, 0, "test.cpp");
272 E.Members.emplace_back(Args: "X", Args: "0");
273 E.Members.emplace_back(Args: "Y", Args: "1");
274 ExpectedNamespaceWithEnum.Children.Enums.emplace_back(args: std::move(E));
275 CheckNamespaceInfo(Expected: &ExpectedNamespaceWithEnum, Actual: NamespaceWithEnum);
276
277 NamespaceInfo *NamespaceWithScopedEnum = InfoAsNamespace(I: Infos[1].get());
278 NamespaceInfo ExpectedNamespaceWithScopedEnum(EmptySID);
279 EnumInfo G;
280 G.Name = "G";
281 G.Scoped = true;
282 G.DefLoc = Location(0, 0, "test.cpp");
283 G.Members.emplace_back(Args: "A", Args: "0");
284 G.Members.emplace_back(Args: "B", Args: "1");
285 ExpectedNamespaceWithScopedEnum.Children.Enums.emplace_back(args: std::move(G));
286 CheckNamespaceInfo(Expected: &ExpectedNamespaceWithScopedEnum, Actual: NamespaceWithScopedEnum);
287}
288
289TEST(SerializeTest, emitUndefinedRecordInfo) {
290 EmittedInfoList Infos;
291 ExtractInfosFromCode(Code: "class E;", NumExpectedInfos: 2, /*Public=*/false, EmittedInfos&: Infos);
292
293 RecordInfo *E = InfoAsRecord(I: Infos[0].get());
294 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
295 ExpectedE.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
296 Args: InfoType::IT_namespace);
297 ExpectedE.TagType = TagTypeKind::Class;
298 ExpectedE.Loc.emplace_back(Args: 0, Args: 0, Args: "test.cpp");
299 CheckRecordInfo(Expected: &ExpectedE, Actual: E);
300}
301
302TEST(SerializeTest, emitRecordMemberInfo) {
303 EmittedInfoList Infos;
304 ExtractInfosFromCode(Code: "struct E { int I; };", NumExpectedInfos: 2, /*Public=*/false, EmittedInfos&: Infos);
305
306 RecordInfo *E = InfoAsRecord(I: Infos[0].get());
307 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
308 ExpectedE.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
309 Args: InfoType::IT_namespace);
310 ExpectedE.TagType = TagTypeKind::Struct;
311 ExpectedE.DefLoc = Location(0, 0, "test.cpp");
312 ExpectedE.Members.emplace_back(Args: TypeInfo("int"), Args: "I",
313 Args: AccessSpecifier::AS_public);
314 CheckRecordInfo(Expected: &ExpectedE, Actual: E);
315}
316
317TEST(SerializeTest, emitInternalRecordInfo) {
318 EmittedInfoList Infos;
319 ExtractInfosFromCode(Code: "class E { class G {}; };", NumExpectedInfos: 4, /*Public=*/false, EmittedInfos&: Infos);
320
321 RecordInfo *E = InfoAsRecord(I: Infos[0].get());
322 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
323 ExpectedE.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
324 Args: InfoType::IT_namespace);
325 ExpectedE.DefLoc = Location(0, 0, "test.cpp");
326 ExpectedE.TagType = TagTypeKind::Class;
327 CheckRecordInfo(Expected: &ExpectedE, Actual: E);
328
329 RecordInfo *G = InfoAsRecord(I: Infos[2].get());
330 llvm::SmallString<128> ExpectedGPath("GlobalNamespace/E");
331 llvm::sys::path::native(path&: ExpectedGPath);
332 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/ExpectedGPath);
333 ExpectedG.DefLoc = Location(0, 0, "test.cpp");
334 ExpectedG.TagType = TagTypeKind::Class;
335 ExpectedG.Namespace.emplace_back(Args: EmptySID, Args: "E", Args: InfoType::IT_record);
336 ExpectedG.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
337 Args: InfoType::IT_namespace);
338 CheckRecordInfo(Expected: &ExpectedG, Actual: G);
339}
340
341TEST(SerializeTest, emitPublicAnonymousNamespaceInfo) {
342 EmittedInfoList Infos;
343 ExtractInfosFromCode(Code: "namespace { class A; }", NumExpectedInfos: 0, /*Public=*/true, EmittedInfos&: Infos);
344}
345
346TEST(SerializeTest, emitPublicFunctionInternalInfo) {
347 EmittedInfoList Infos;
348 ExtractInfosFromCode(Code: "int F() { class G {}; return 0; };", NumExpectedInfos: 1, /*Public=*/true,
349 EmittedInfos&: Infos);
350
351 NamespaceInfo *BWithFunction = InfoAsNamespace(I: Infos[0].get());
352 NamespaceInfo ExpectedBWithFunction(EmptySID);
353 FunctionInfo F;
354 F.Name = "F";
355 F.ReturnType = TypeInfo("int");
356 F.DefLoc = Location(0, 0, "test.cpp");
357 F.Access = AccessSpecifier::AS_none;
358 ExpectedBWithFunction.Children.Functions.emplace_back(args: std::move(F));
359 CheckNamespaceInfo(Expected: &ExpectedBWithFunction, Actual: BWithFunction);
360}
361
362TEST(SerializeTest, emitInlinedFunctionInfo) {
363 EmittedInfoList Infos;
364 ExtractInfosFromCode(Code: "inline void F(int I) { };", NumExpectedInfos: 1, /*Public=*/true, EmittedInfos&: Infos);
365
366 NamespaceInfo *BWithFunction = InfoAsNamespace(I: Infos[0].get());
367 NamespaceInfo ExpectedBWithFunction(EmptySID);
368 FunctionInfo F;
369 F.Name = "F";
370 F.ReturnType = TypeInfo("void");
371 F.DefLoc = Location(0, 0, "test.cpp");
372 F.Params.emplace_back(Args: TypeInfo("int"), Args: "I");
373 F.Access = AccessSpecifier::AS_none;
374 ExpectedBWithFunction.Children.Functions.emplace_back(args: std::move(F));
375 CheckNamespaceInfo(Expected: &ExpectedBWithFunction, Actual: BWithFunction);
376}
377
378TEST(SerializeTest, emitInheritedRecordInfo) {
379 EmittedInfoList Infos;
380 ExtractInfosFromCode(Code: R"raw(class F { protected: void set(int N); };
381class G { public: int get() { return 1; } protected: int I; };
382class E : public F, virtual private G {};
383class H : private E {};
384template <typename T>
385class I {} ;
386class J : public I<int> {} ;)raw",
387 NumExpectedInfos: 14, /*Public=*/false, EmittedInfos&: Infos);
388
389 RecordInfo *F = InfoAsRecord(I: Infos[0].get());
390 RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
391 ExpectedF.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
392 Args: InfoType::IT_namespace, Args: "");
393 ExpectedF.TagType = TagTypeKind::Class;
394 ExpectedF.DefLoc = Location(0, 0, "test.cpp");
395 CheckRecordInfo(Expected: &ExpectedF, Actual: F);
396
397 RecordInfo *G = InfoAsRecord(I: Infos[3].get());
398 RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");
399 ExpectedG.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
400 Args: InfoType::IT_namespace);
401 ExpectedG.TagType = TagTypeKind::Class;
402 ExpectedG.DefLoc = Location(0, 0, "test.cpp");
403 ExpectedG.Members.emplace_back(Args: TypeInfo("int"), Args: "I",
404 Args: AccessSpecifier::AS_protected);
405 CheckRecordInfo(Expected: &ExpectedG, Actual: G);
406
407 RecordInfo *E = InfoAsRecord(I: Infos[6].get());
408 RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
409 ExpectedE.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
410 Args: InfoType::IT_namespace);
411 ExpectedE.Parents.emplace_back(Args: EmptySID, /*Name=*/Args: "F", Args: InfoType::IT_record,
412 /*QualName=*/Args: "", /*Path*=*/Args: "GlobalNamespace");
413 ExpectedE.VirtualParents.emplace_back(Args: EmptySID, /*Name=*/Args: "G",
414 Args: InfoType::IT_record, /*QualName=*/Args: "G",
415 /*Path*=*/Args: "GlobalNamespace");
416 ExpectedE.Bases.emplace_back(args: EmptySID, /*Name=*/args: "F",
417 /*Path=*/args: "GlobalNamespace", args: false,
418 args: AccessSpecifier::AS_public, args: true);
419 FunctionInfo FunctionSet;
420 FunctionSet.Name = "set";
421 FunctionSet.ReturnType = TypeInfo("void");
422 FunctionSet.Loc.emplace_back();
423 FunctionSet.Params.emplace_back(Args: TypeInfo("int"), Args: "N");
424 FunctionSet.Namespace.emplace_back(Args: EmptySID, Args: "F", Args: InfoType::IT_record);
425 FunctionSet.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
426 Args: InfoType::IT_namespace);
427 FunctionSet.Access = AccessSpecifier::AS_protected;
428 FunctionSet.IsMethod = true;
429 ExpectedE.Bases.back().Children.Functions.emplace_back(
430 args: std::move(FunctionSet));
431 ExpectedE.Bases.emplace_back(args: EmptySID, /*Name=*/args: "G",
432 /*Path=*/args: "GlobalNamespace", args: true,
433 args: AccessSpecifier::AS_private, args: true);
434 FunctionInfo FunctionGet;
435 FunctionGet.Name = "get";
436 FunctionGet.ReturnType = TypeInfo("int");
437 FunctionGet.DefLoc = Location();
438 FunctionGet.Namespace.emplace_back(Args: EmptySID, Args: "G", Args: InfoType::IT_record);
439 FunctionGet.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
440 Args: InfoType::IT_namespace);
441 FunctionGet.Access = AccessSpecifier::AS_private;
442 FunctionGet.IsMethod = true;
443 ExpectedE.Bases.back().Children.Functions.emplace_back(
444 args: std::move(FunctionGet));
445 ExpectedE.Bases.back().Members.emplace_back(Args: TypeInfo("int"), Args: "I",
446 Args: AccessSpecifier::AS_private);
447 ExpectedE.DefLoc = Location(0, 0, "test.cpp");
448 ExpectedE.TagType = TagTypeKind::Class;
449 CheckRecordInfo(Expected: &ExpectedE, Actual: E);
450
451 RecordInfo *H = InfoAsRecord(I: Infos[8].get());
452 RecordInfo ExpectedH(EmptySID, /*Name=*/"H", /*Path=*/"GlobalNamespace");
453 ExpectedH.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
454 Args: InfoType::IT_namespace);
455 ExpectedH.TagType = TagTypeKind::Class;
456 ExpectedH.DefLoc = Location(0, 0, "test.cpp");
457 ExpectedH.Parents.emplace_back(Args: EmptySID, /*Name=*/Args: "E", Args: InfoType::IT_record,
458 /*QualName=*/Args: "E", /*Path=*/Args: "GlobalNamespace");
459 ExpectedH.VirtualParents.emplace_back(Args: EmptySID, /*Name=*/Args: "G",
460 Args: InfoType::IT_record, /*QualName=*/Args: "G",
461 /*Path=*/Args: "GlobalNamespace");
462 ExpectedH.Bases.emplace_back(args: EmptySID, /*Name=*/args: "E",
463 /*Path=*/args: "GlobalNamespace", args: false,
464 args: AccessSpecifier::AS_private, args: true);
465 ExpectedH.Bases.emplace_back(args: EmptySID, /*Name=*/args: "F",
466 /*Path=*/args: "GlobalNamespace", args: false,
467 args: AccessSpecifier::AS_private, args: false);
468 FunctionInfo FunctionSetNew;
469 FunctionSetNew.Name = "set";
470 FunctionSetNew.ReturnType = TypeInfo("void");
471 FunctionSetNew.Loc.emplace_back();
472 FunctionSetNew.Params.emplace_back(Args: TypeInfo("int"), Args: "N");
473 FunctionSetNew.Namespace.emplace_back(Args: EmptySID, Args: "F", Args: InfoType::IT_record);
474 FunctionSetNew.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
475 Args: InfoType::IT_namespace);
476 FunctionSetNew.Access = AccessSpecifier::AS_private;
477 FunctionSetNew.IsMethod = true;
478 ExpectedH.Bases.back().Children.Functions.emplace_back(
479 args: std::move(FunctionSetNew));
480 ExpectedH.Bases.emplace_back(args: EmptySID, /*Name=*/args: "G",
481 /*Path=*/args: "GlobalNamespace", args: true,
482 args: AccessSpecifier::AS_private, args: false);
483 FunctionInfo FunctionGetNew;
484 FunctionGetNew.Name = "get";
485 FunctionGetNew.ReturnType = TypeInfo("int");
486 FunctionGetNew.DefLoc = Location();
487 FunctionGetNew.Namespace.emplace_back(Args: EmptySID, Args: "G", Args: InfoType::IT_record);
488 FunctionGetNew.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
489 Args: InfoType::IT_namespace);
490 FunctionGetNew.Access = AccessSpecifier::AS_private;
491 FunctionGetNew.IsMethod = true;
492 ExpectedH.Bases.back().Children.Functions.emplace_back(
493 args: std::move(FunctionGetNew));
494 ExpectedH.Bases.back().Members.emplace_back(Args: TypeInfo("int"), Args: "I",
495 Args: AccessSpecifier::AS_private);
496 CheckRecordInfo(Expected: &ExpectedH, Actual: H);
497
498 RecordInfo *I = InfoAsRecord(I: Infos[10].get());
499 RecordInfo ExpectedI(EmptySID, /*Name=*/"I", /*Path=*/"GlobalNamespace");
500 ExpectedI.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
501 Args: InfoType::IT_namespace);
502 ExpectedI.TagType = TagTypeKind::Class;
503 ExpectedI.DefLoc = Location(0, 0, "test.cpp");
504 CheckRecordInfo(Expected: &ExpectedI, Actual: I);
505
506 RecordInfo *J = InfoAsRecord(I: Infos[12].get());
507 RecordInfo ExpectedJ(EmptySID, /*Name=*/"J", /*Path=*/"GlobalNamespace");
508 ExpectedJ.Namespace.emplace_back(Args: EmptySID, Args: "GlobalNamespace",
509 Args: InfoType::IT_namespace);
510 ExpectedJ.Parents.emplace_back(Args: EmptySID, /*Name=*/Args: "I<int>",
511 Args: InfoType::IT_record);
512 ExpectedJ.Bases.emplace_back(args: EmptySID, /*Name=*/args: "I<int>",
513 /*Path=*/args: "GlobalNamespace", args: false,
514 args: AccessSpecifier::AS_public, args: true);
515 ExpectedJ.DefLoc = Location(0, 0, "test.cpp");
516 ExpectedJ.TagType = TagTypeKind::Class;
517 CheckRecordInfo(Expected: &ExpectedJ, Actual: J);
518}
519
520TEST(SerializeTest, emitModulePublicLFunctions) {
521 EmittedInfoList Infos;
522 std::vector<std::string> Args;
523 Args.push_back(x: "-fmodules-ts");
524 ExtractInfosFromCodeWithArgs(Code: R"raw(export module M;
525int moduleFunction(int x, double d = 3.2 - 1.0);
526static int staticModuleFunction(int x);
527export double exportedModuleFunction(double y);)raw",
528 NumExpectedInfos: 2, /*Public=*/true, EmittedInfos&: Infos, Args);
529
530 NamespaceInfo *BWithFunction = InfoAsNamespace(I: Infos[0].get());
531 NamespaceInfo ExpectedBWithFunction(EmptySID);
532 FunctionInfo F;
533 F.Name = "moduleFunction";
534 F.ReturnType = TypeInfo("int");
535 F.Loc.emplace_back(Args: 0, Args: 0, Args: "test.cpp");
536 F.Params.emplace_back(Args: TypeInfo("int"), Args: "x");
537 F.Params.emplace_back(Args: TypeInfo("double"), Args: "d");
538 F.Params.back().DefaultValue = "3.2 - 1.0";
539 F.Access = AccessSpecifier::AS_none;
540 ExpectedBWithFunction.Children.Functions.emplace_back(args: std::move(F));
541 CheckNamespaceInfo(Expected: &ExpectedBWithFunction, Actual: BWithFunction);
542
543 NamespaceInfo *BWithExportedFunction = InfoAsNamespace(I: Infos[1].get());
544 NamespaceInfo ExpectedBWithExportedFunction(EmptySID);
545 FunctionInfo ExportedF;
546 ExportedF.Name = "exportedModuleFunction";
547 ExportedF.ReturnType =
548 TypeInfo(Reference(EmptySID, "double", InfoType::IT_default));
549 ExportedF.Loc.emplace_back(Args: 0, Args: 0, Args: "test.cpp");
550 ExportedF.Params.emplace_back(Args: TypeInfo("double"), Args: "y");
551 ExportedF.Access = AccessSpecifier::AS_none;
552 ExpectedBWithExportedFunction.Children.Functions.emplace_back(
553 args: std::move(ExportedF));
554 CheckNamespaceInfo(Expected: &ExpectedBWithExportedFunction, Actual: BWithExportedFunction);
555}
556
557// Test serialization of child records in namespaces and other records
558TEST(SerializeTest, emitChildRecords) {
559 EmittedInfoList Infos;
560 ExtractInfosFromCode(Code: "class A { class B {}; }; namespace { class C {}; } ", NumExpectedInfos: 8,
561 /*Public=*/false, EmittedInfos&: Infos);
562
563 NamespaceInfo *ParentA = InfoAsNamespace(I: Infos[1].get());
564 NamespaceInfo ExpectedParentA(EmptySID);
565 ExpectedParentA.Children.Records.emplace_back(
566 args: EmptySID, args: "A", args: InfoType::IT_record, args: "A", args: "GlobalNamespace");
567 CheckNamespaceInfo(Expected: &ExpectedParentA, Actual: ParentA);
568
569 RecordInfo *ParentB = InfoAsRecord(I: Infos[3].get());
570 RecordInfo ExpectedParentB(EmptySID);
571 llvm::SmallString<128> ExpectedParentBPath("GlobalNamespace/A");
572 llvm::sys::path::native(path&: ExpectedParentBPath);
573 ExpectedParentB.Children.Records.emplace_back(
574 args: EmptySID, args: "B", args: InfoType::IT_record, args: "A::B", args&: ExpectedParentBPath);
575 CheckRecordInfo(Expected: &ExpectedParentB, Actual: ParentB);
576
577 NamespaceInfo *ParentC = InfoAsNamespace(I: Infos[7].get());
578 NamespaceInfo ExpectedParentC(EmptySID);
579 ExpectedParentC.Children.Records.emplace_back(
580 args: EmptySID, args: "C", args: InfoType::IT_record, args: "C", args: "@nonymous_namespace");
581 CheckNamespaceInfo(Expected: &ExpectedParentC, Actual: ParentC);
582}
583
584// Test serialization of child namespaces
585TEST(SerializeTest, emitChildNamespaces) {
586 EmittedInfoList Infos;
587 ExtractInfosFromCode(Code: "namespace A { namespace B { } }", NumExpectedInfos: 4, /*Public=*/false,
588 EmittedInfos&: Infos);
589
590 NamespaceInfo *ParentA = InfoAsNamespace(I: Infos[1].get());
591 NamespaceInfo ExpectedParentA(EmptySID);
592 ExpectedParentA.Children.Namespaces.emplace_back(args: EmptySID, args: "A",
593 args: InfoType::IT_namespace);
594 CheckNamespaceInfo(Expected: &ExpectedParentA, Actual: ParentA);
595
596 NamespaceInfo *ParentB = InfoAsNamespace(I: Infos[3].get());
597 NamespaceInfo ExpectedParentB(EmptySID);
598 ExpectedParentB.Children.Namespaces.emplace_back(
599 args: EmptySID, args: "B", args: InfoType::IT_namespace, args: "A::B", args: "A");
600 CheckNamespaceInfo(Expected: &ExpectedParentB, Actual: ParentB);
601}
602
603TEST(SerializeTests, emitTypedefs) {
604 EmittedInfoList Infos;
605 ExtractInfosFromCode(Code: "typedef int MyInt; using MyDouble = double;", NumExpectedInfos: 2,
606 /*Public=*/false, EmittedInfos&: Infos);
607
608 // First info will be the global namespace with the typedef in it.
609 NamespaceInfo *GlobalNS1 = InfoAsNamespace(I: Infos[0].get());
610 ASSERT_EQ(1u, GlobalNS1->Children.Typedefs.size());
611
612 const TypedefInfo &FirstTD = GlobalNS1->Children.Typedefs[0];
613 EXPECT_EQ("MyInt", FirstTD.Name);
614 EXPECT_FALSE(FirstTD.IsUsing);
615 EXPECT_EQ("int", FirstTD.Underlying.Type.Name);
616
617 // The second will be another global namespace with the using in it (the
618 // global namespace is duplicated because the items haven't been merged at the
619 // serialization phase of processing).
620 NamespaceInfo *GlobalNS2 = InfoAsNamespace(I: Infos[1].get());
621 ASSERT_EQ(1u, GlobalNS2->Children.Typedefs.size());
622
623 // Second is the "using" typedef.
624 const TypedefInfo &SecondTD = GlobalNS2->Children.Typedefs[0];
625 EXPECT_EQ("MyDouble", SecondTD.Name);
626 EXPECT_TRUE(SecondTD.IsUsing);
627 EXPECT_EQ("double", SecondTD.Underlying.Type.Name);
628}
629
630TEST(SerializeTests, emitFunctionTemplate) {
631 EmittedInfoList Infos;
632 // A template and a specialization.
633 ExtractInfosFromCode(Code: "template<typename T = int> bool GetFoo(T);\n"
634 "template<> bool GetFoo<bool>(bool);",
635 NumExpectedInfos: 2,
636 /*Public=*/false, EmittedInfos&: Infos);
637
638 // First info will be the global namespace.
639 NamespaceInfo *GlobalNS1 = InfoAsNamespace(I: Infos[0].get());
640 ASSERT_EQ(1u, GlobalNS1->Children.Functions.size());
641
642 const FunctionInfo &Func1 = GlobalNS1->Children.Functions[0];
643 EXPECT_EQ("GetFoo", Func1.Name);
644 ASSERT_TRUE(Func1.Template);
645 EXPECT_FALSE(Func1.Template->Specialization); // Not a specialization.
646
647 // Template parameter.
648 ASSERT_EQ(1u, Func1.Template->Params.size());
649 EXPECT_EQ("typename T = int", Func1.Template->Params[0].Contents);
650
651 // The second will be another global namespace with the function in it (the
652 // global namespace is duplicated because the items haven't been merged at the
653 // serialization phase of processing).
654 NamespaceInfo *GlobalNS2 = InfoAsNamespace(I: Infos[1].get());
655 ASSERT_EQ(1u, GlobalNS2->Children.Functions.size());
656
657 // This one is a template specialization.
658 const FunctionInfo &Func2 = GlobalNS2->Children.Functions[0];
659 EXPECT_EQ("GetFoo", Func2.Name);
660 ASSERT_TRUE(Func2.Template);
661 EXPECT_TRUE(Func2.Template->Params.empty()); // No template params.
662 ASSERT_TRUE(Func2.Template->Specialization);
663
664 // Specialization values.
665 ASSERT_EQ(1u, Func2.Template->Specialization->Params.size());
666 EXPECT_EQ("bool", Func2.Template->Specialization->Params[0].Contents);
667 EXPECT_EQ(Func1.USR, Func2.Template->Specialization->SpecializationOf);
668
669 EXPECT_EQ("bool", Func2.ReturnType.Type.Name);
670}
671
672TEST(SerializeTests, emitClassTemplate) {
673 EmittedInfoList Infos;
674 // This will generate 2x the number of infos: each Record will be followed by
675 // a copy of the global namespace containing it (this test checks the data
676 // pre-merge).
677 ExtractInfosFromCode(
678 Code: "template<int I> class MyTemplate { int i[I]; };\n"
679 "template<> class MyTemplate<0> {};\n"
680 "template<typename T, int U = 1> class OtherTemplate {};\n"
681 "template<int U> class OtherTemplate<MyTemplate<0>, U> {};",
682 NumExpectedInfos: 8,
683 /*Public=*/false, EmittedInfos&: Infos);
684
685 // First record.
686 const RecordInfo *Rec1 = InfoAsRecord(I: Infos[0].get());
687 EXPECT_EQ("MyTemplate", Rec1->Name);
688 ASSERT_TRUE(Rec1->Template);
689 EXPECT_FALSE(Rec1->Template->Specialization); // Not a specialization.
690
691 // First record template parameter.
692 ASSERT_EQ(1u, Rec1->Template->Params.size());
693 EXPECT_EQ("int I", Rec1->Template->Params[0].Contents);
694
695 // Second record.
696 const RecordInfo *Rec2 = InfoAsRecord(I: Infos[2].get());
697 EXPECT_EQ("MyTemplate", Rec2->Name);
698 ASSERT_TRUE(Rec2->Template);
699 EXPECT_TRUE(Rec2->Template->Params.empty()); // No template params.
700 ASSERT_TRUE(Rec2->Template->Specialization);
701
702 // Second record specialization values.
703 ASSERT_EQ(1u, Rec2->Template->Specialization->Params.size());
704 EXPECT_EQ("0", Rec2->Template->Specialization->Params[0].Contents);
705 EXPECT_EQ(Rec1->USR, Rec2->Template->Specialization->SpecializationOf);
706
707 // Third record.
708 const RecordInfo *Rec3 = InfoAsRecord(I: Infos[4].get());
709 EXPECT_EQ("OtherTemplate", Rec3->Name);
710 ASSERT_TRUE(Rec3->Template);
711
712 // Third record template parameters.
713 ASSERT_EQ(2u, Rec3->Template->Params.size());
714 EXPECT_EQ("typename T", Rec3->Template->Params[0].Contents);
715 EXPECT_EQ("int U = 1", Rec3->Template->Params[1].Contents);
716
717 // Fourth record.
718 const RecordInfo *Rec4 = InfoAsRecord(I: Infos[6].get());
719 EXPECT_EQ("OtherTemplate", Rec3->Name);
720 ASSERT_TRUE(Rec4->Template);
721 ASSERT_TRUE(Rec4->Template->Specialization);
722
723 // Fourth record template + specialization parameters.
724 ASSERT_EQ(1u, Rec4->Template->Params.size());
725 EXPECT_EQ("int U", Rec4->Template->Params[0].Contents);
726 ASSERT_EQ(2u, Rec4->Template->Specialization->Params.size());
727 EXPECT_EQ("MyTemplate<0>",
728 Rec4->Template->Specialization->Params[0].Contents);
729 EXPECT_EQ("U", Rec4->Template->Specialization->Params[1].Contents);
730}
731
732} // namespace doc
733} // end namespace clang
734

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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