1 //===-- clang-doc/SerializeTest.cpp ---------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
19 class ClangDocSerializeTestVisitor
20 : public RecursiveASTVisitor
<ClangDocSerializeTestVisitor
> {
22 EmittedInfoList
&EmittedInfos
;
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
);
35 ClangDocSerializeTestVisitor(EmittedInfoList
&EmittedInfos
, bool Public
)
36 : EmittedInfos(EmittedInfos
), Public(Public
) {}
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
);
42 EmittedInfos
.emplace_back(std::move(I
.first
));
44 EmittedInfos
.emplace_back(std::move(I
.second
));
48 bool VisitNamespaceDecl(const NamespaceDecl
*D
) { return mapDecl(D
); }
50 bool VisitFunctionDecl(const FunctionDecl
*D
) {
51 // Don't visit CXXMethodDecls twice
52 if (dyn_cast
<CXXMethodDecl
>(D
))
57 bool VisitCXXMethodDecl(const CXXMethodDecl
*D
) { return mapDecl(D
); }
59 bool VisitRecordDecl(const RecordDecl
*D
) { return mapDecl(D
); }
61 bool VisitEnumDecl(const EnumDecl
*D
) { return mapDecl(D
); }
63 bool VisitTypedefDecl(const TypedefDecl
*D
) { return mapDecl(D
); }
65 bool VisitTypeAliasDecl(const TypeAliasDecl
*D
) { return mapDecl(D
); }
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());
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());
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>());
95 CommentInfo *Brief = TopComment.Children.back().get();
96 Brief->Kind = "ParagraphComment";
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;
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
);
113 NamespaceInfo
*A
= InfoAsNamespace(Infos
[0].get());
114 NamespaceInfo
ExpectedA(EmptySID
, "A");
115 CheckNamespaceInfo(&ExpectedA
, A
);
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
);
122 NamespaceInfo
*BWithFunction
= InfoAsNamespace(Infos
[4].get());
123 NamespaceInfo
ExpectedBWithFunction(EmptySID
);
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
);
135 TEST(SerializeTest
, emitAnonymousNamespaceInfo
) {
136 EmittedInfoList Infos
;
137 ExtractInfosFromCode("namespace { }", 2, /*Public=*/false, Infos
);
139 NamespaceInfo
*A
= InfoAsNamespace(Infos
[0].get());
140 NamespaceInfo
ExpectedA(EmptySID
);
141 ExpectedA
.Name
= "@nonymous_namespace";
142 CheckNamespaceInfo(&ExpectedA
, A
);
145 // Test serialization of record declarations.
146 TEST(SerializeTest
, emitRecordInfo
) {
147 EmittedInfoList Infos
;
148 ExtractInfosFromCode(R
"raw(class E {
155 void ProtectedMethod();
157 template <typename T>
159 void TemplateMethod();
162 void F<int>::TemplateMethod();
163 typedef struct {} G;)raw",
164 10, /*Public=*/false, Infos
);
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
);
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
);
194 RecordInfo
*RecordWithMethod
= InfoAsRecord(Infos
[3].get());
195 RecordInfo
ExpectedRecordWithMethod(EmptySID
);
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
);
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
);
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
);
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
);
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
);
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
);
268 NamespaceInfo
*NamespaceWithEnum
= InfoAsNamespace(Infos
[0].get());
269 NamespaceInfo
ExpectedNamespaceWithEnum(EmptySID
);
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
);
278 NamespaceInfo
*NamespaceWithScopedEnum
= InfoAsNamespace(Infos
[1].get());
279 NamespaceInfo
ExpectedNamespaceWithScopedEnum(EmptySID
);
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
);
290 TEST(SerializeTest
, emitUndefinedRecordInfo
) {
291 EmittedInfoList Infos
;
292 ExtractInfosFromCode("class E;", 2, /*Public=*/false, Infos
);
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
);
303 TEST(SerializeTest
, emitRecordMemberInfo
) {
304 EmittedInfoList Infos
;
305 ExtractInfosFromCode("struct E { int I; };", 2, /*Public=*/false, Infos
);
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
);
318 TEST(SerializeTest
, emitInternalRecordInfo
) {
319 EmittedInfoList Infos
;
320 ExtractInfosFromCode("class E { class G {}; };", 4, /*Public=*/false, Infos
);
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
);
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
);
342 TEST(SerializeTest
, emitPublicAnonymousNamespaceInfo
) {
343 EmittedInfoList Infos
;
344 ExtractInfosFromCode("namespace { class A; }", 0, /*Public=*/true, Infos
);
347 TEST(SerializeTest
, emitPublicFunctionInternalInfo
) {
348 EmittedInfoList Infos
;
349 ExtractInfosFromCode("int F() { class G {}; return 0; };", 1, /*Public=*/true,
352 NamespaceInfo
*BWithFunction
= InfoAsNamespace(Infos
[0].get());
353 NamespaceInfo
ExpectedBWithFunction(EmptySID
);
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
);
363 TEST(SerializeTest
, emitInlinedFunctionInfo
) {
364 EmittedInfoList Infos
;
365 ExtractInfosFromCode("inline void F(int I) { };", 1, /*Public=*/true, Infos
);
367 NamespaceInfo
*BWithFunction
= InfoAsNamespace(Infos
[0].get());
368 NamespaceInfo
ExpectedBWithFunction(EmptySID
);
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
);
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>
387 class J : public I<int> {} ;)raw",
388 14, /*Public=*/false, Infos
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
531 NamespaceInfo
*BWithFunction
= InfoAsNamespace(Infos
[0].get());
532 NamespaceInfo
ExpectedBWithFunction(EmptySID
);
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
);
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
);
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
);
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
);
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
);
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
);
585 // Test serialization of child namespaces
586 TEST(SerializeTest
, emitChildNamespaces
) {
587 EmittedInfoList Infos
;
588 ExtractInfosFromCode("namespace A { namespace B { } }", 4, /*Public=*/false,
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
);
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
);
604 TEST(SerializeTests
, emitTypedefs
) {
605 EmittedInfoList Infos
;
606 ExtractInfosFromCode("typedef int MyInt; using MyDouble = double;", 2,
607 /*Public=*/false, Infos
);
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());
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
);
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());
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
);
631 TEST(SerializeTests
, emitFunctionTemplate
) {
632 EmittedInfoList Infos
;
633 // A template and a specialization.
634 ExtractInfosFromCode("template<typename T = int> void GetFoo(T);\n"
635 "template<> void GetFoo<bool>(bool);",
637 /*Public=*/false, Infos
);
639 // First info will be the global namespace.
640 NamespaceInfo
*GlobalNS1
= InfoAsNamespace(Infos
[0].get());
641 ASSERT_EQ(1u, GlobalNS1
->Children
.Functions
.size());
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.
648 // Template parameter.
649 ASSERT_EQ(1u, Func1
.Template
->Params
.size());
650 EXPECT_EQ("typename T = int", Func1
.Template
->Params
[0].Contents
);
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());
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
);
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
);
671 TEST(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
676 ExtractInfosFromCode(
677 "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> {};",
682 /*Public=*/false, Infos
);
685 const RecordInfo
*Rec1
= InfoAsRecord(Infos
[0].get());
686 EXPECT_EQ("MyTemplate", Rec1
->Name
);
687 ASSERT_TRUE(Rec1
->Template
);
688 EXPECT_FALSE(Rec1
->Template
->Specialization
); // Not a specialization.
690 // First record template parameter.
691 ASSERT_EQ(1u, Rec1
->Template
->Params
.size());
692 EXPECT_EQ("int I", Rec1
->Template
->Params
[0].Contents
);
695 const RecordInfo
*Rec2
= InfoAsRecord(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
);
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
);
707 const RecordInfo
*Rec3
= InfoAsRecord(Infos
[4].get());
708 EXPECT_EQ("OtherTemplate", Rec3
->Name
);
709 ASSERT_TRUE(Rec3
->Template
);
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
);
717 const RecordInfo
*Rec4
= InfoAsRecord(Infos
[6].get());
718 EXPECT_EQ("OtherTemplate", Rec3
->Name
);
719 ASSERT_TRUE(Rec4
->Template
);
720 ASSERT_TRUE(Rec4
->Template
->Specialization
);
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
);
732 } // end namespace clang