File indexing completed on 2024-05-19 05:42:05
0001 // ct_lvtclp_testudt.t.cpp -*-C++-*- 0002 0003 /* 0004 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk> 0005 // SPDX-License-Identifier: Apache-2.0 0006 // 0007 // Licensed under the Apache License, Version 2.0 (the "License"); 0008 // you may not use this file except in compliance with the License. 0009 // You may obtain a copy of the License at 0010 // 0011 // http://www.apache.org/licenses/LICENSE-2.0 0012 // 0013 // Unless required by applicable law or agreed to in writing, software 0014 // distributed under the License is distributed on an "AS IS" BASIS, 0015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0016 // See the License for the specific language governing permissions and 0017 // limitations under the License. 0018 */ 0019 0020 // This file is home to tests for adding user defined types to the database 0021 0022 #include <ct_lvtmdb_fileobject.h> 0023 #include <ct_lvtmdb_functionobject.h> 0024 #include <ct_lvtmdb_methodobject.h> 0025 #include <ct_lvtmdb_namespaceobject.h> 0026 #include <ct_lvtmdb_objectstore.h> 0027 #include <ct_lvtmdb_typeobject.h> 0028 0029 #include <ct_lvtclp_testutil.h> 0030 #include <ct_lvtshr_graphenums.h> 0031 0032 #include <algorithm> 0033 #include <initializer_list> 0034 #include <string> 0035 #include <tuple> 0036 #include <unordered_set> 0037 #include <vector> 0038 0039 #include <catch2-local-includes.h> 0040 0041 #include <clang/Basic/Version.h> 0042 0043 using namespace Codethink::lvtclp; 0044 using namespace Codethink::lvtmdb; 0045 using namespace Codethink; 0046 0047 using UDTKind = Codethink::lvtshr::UDTKind; 0048 0049 const PyDefaultGilReleasedContext defaultGilContextForTesting; 0050 0051 TEST_CASE("User defined type") 0052 { 0053 const static char *source = "namespace foo { class C {}; class D; }"; 0054 ObjectStore session; 0055 REQUIRE(Test_Util::runOnCode(session, source, "testUserDefinedType.cpp")); 0056 0057 TypeObject *C = nullptr; 0058 TypeObject *D = nullptr; 0059 NamespaceObject *foo = nullptr; 0060 FileObject *file = nullptr; 0061 0062 session.withROLock([&] { 0063 C = session.getType("foo::C"); 0064 D = session.getType("foo::D"); 0065 foo = session.getNamespace("foo"); 0066 file = session.getFile("testUserDefinedType.cpp"); 0067 }); 0068 0069 REQUIRE(C); 0070 REQUIRE(D); 0071 REQUIRE(foo); 0072 REQUIRE(file); 0073 0074 C->withROLock([&] { 0075 REQUIRE(C->name() == "C"); 0076 REQUIRE(C->kind() == UDTKind::Class); 0077 REQUIRE(C->access() == lvtshr::AccessSpecifier::e_none); 0078 REQUIRE(C->parentNamespace() == foo); 0079 REQUIRE(!C->parent()); 0080 }); 0081 0082 D->withROLock([&] { 0083 REQUIRE(D->name() == "D"); 0084 REQUIRE(D->kind() == UDTKind::Class); 0085 REQUIRE(D->access() == lvtshr::AccessSpecifier::e_none); 0086 REQUIRE(D->parentNamespace() == foo); 0087 REQUIRE(!D->parent()); 0088 }); 0089 0090 foo->withROLock([&] { 0091 const auto classChildren = foo->typeChildren(); 0092 auto childIt = std::find(classChildren.begin(), classChildren.end(), C); 0093 REQUIRE(childIt != classChildren.end()); 0094 childIt = std::find(classChildren.begin(), classChildren.end(), D); 0095 REQUIRE(childIt != classChildren.end()); 0096 }); 0097 0098 file->withROLock([&] { 0099 const auto classes = file->types(); 0100 auto classes_it = std::find(classes.begin(), classes.end(), C); 0101 REQUIRE(classes_it != classes.end()); 0102 classes_it = std::find(classes.begin(), classes.end(), D); 0103 REQUIRE(classes_it != classes.end()); 0104 }); 0105 C->withROLock([&] { 0106 auto files = C->files(); 0107 auto files_it = std::find(files.begin(), files.end(), file); 0108 REQUIRE(files_it != files.end()); 0109 }); 0110 0111 D->withROLock([&] { 0112 auto files = D->files(); 0113 auto files_it = std::find(files.begin(), files.end(), file); 0114 REQUIRE(files_it != files.end()); 0115 }); 0116 } 0117 0118 TEST_CASE("Struct declaration") 0119 { 0120 const static char *source = "struct S {};"; 0121 ObjectStore session; 0122 REQUIRE(Test_Util::runOnCode(session, source, "testStructDeclaration.cpp")); 0123 0124 // assume things we tested in testUserDefinedType are still good here 0125 TypeObject *S = nullptr; 0126 session.withROLock([&] { 0127 S = session.getType("S"); 0128 }); 0129 REQUIRE(S); 0130 0131 S->withROLock([&] { 0132 REQUIRE(S->kind() == UDTKind::Struct); 0133 }); 0134 } 0135 0136 TEST_CASE("Union declaration") 0137 { 0138 const static char *source = "union U {};"; 0139 ObjectStore session; 0140 REQUIRE(Test_Util::runOnCode(session, source, "testUnionDeclaration.cpp")); 0141 0142 TypeObject *U = nullptr; 0143 session.withROLock([&] { 0144 U = session.getType("U"); 0145 }); 0146 // assume things we tested in testUserDefinedType are still good here 0147 REQUIRE(U); 0148 0149 U->withROLock([&] { 0150 REQUIRE(U->kind() == UDTKind::Union); 0151 }); 0152 } 0153 0154 TEST_CASE("Local class") 0155 { 0156 const static char *source = 0157 R"(void fn() 0158 { 0159 class C {}; 0160 } 0161 )"; 0162 ObjectStore session; 0163 REQUIRE(Test_Util::runOnCode(session, source, "testLocalClass.cpp")); 0164 0165 session.withROLock([&] { 0166 REQUIRE(session.types().empty()); 0167 }); 0168 0169 // we skip local classes 0170 } 0171 0172 TEST_CASE("Anon class") 0173 { 0174 const static char *source = "class {} foo;"; 0175 ObjectStore session; 0176 REQUIRE(Test_Util::runOnCode(session, source, "testAnonClass.cpp")); 0177 session.withROLock([&] { 0178 REQUIRE(session.types().empty()); 0179 }); 0180 0181 // we skip anon classes 0182 } 0183 0184 TEST_CASE("Nested classes") 0185 { 0186 const static char *source = R"( 0187 namespace foo { 0188 0189 class C { 0190 public: 0191 class Pub {}; 0192 0193 protected: 0194 class Prot {}; 0195 0196 private: 0197 class Priv {}; 0198 }; 0199 0200 } 0201 )"; 0202 ObjectStore session; 0203 REQUIRE(Test_Util::runOnCode(session, source, "testtNestedClasses.cpp")); 0204 0205 TypeObject *C = nullptr; 0206 TypeObject *Pub = nullptr; 0207 TypeObject *Prot = nullptr; 0208 TypeObject *Priv = nullptr; 0209 NamespaceObject *foo = nullptr; 0210 0211 session.withROLock([&] { 0212 C = session.getType("foo::C"); 0213 Pub = session.getType("foo::C::Pub"); 0214 Prot = session.getType("foo::C::Prot"); 0215 Priv = session.getType("foo::C::Priv"); 0216 foo = session.getNamespace("foo"); 0217 }); 0218 0219 REQUIRE(Priv); 0220 REQUIRE(Prot); 0221 REQUIRE(Pub); 0222 REQUIRE(C); 0223 REQUIRE(foo); 0224 0225 for (const auto& [klass, access] : 0226 std::map<TypeObject *, lvtshr::AccessSpecifier>{{Pub, lvtshr::AccessSpecifier::e_public}, 0227 {Prot, lvtshr::AccessSpecifier::e_protected}, 0228 {Priv, lvtshr::AccessSpecifier::e_private}}) { 0229 klass->withROLock([&, klass = klass, access = access] { 0230 REQUIRE(klass->parentNamespace() == foo); 0231 REQUIRE(klass->parent() == C); 0232 REQUIRE(klass->access() == access); 0233 }); 0234 } 0235 } 0236 0237 TEST_CASE("Is-A") 0238 { 0239 const static char *source = 0240 R"(class C {}; 0241 class D : public C {}; 0242 )"; 0243 0244 ObjectStore session; 0245 REQUIRE(Test_Util::runOnCode(session, source, "testIsA.cpp")); 0246 REQUIRE(Test_Util::isAExists("D", "C", session)); 0247 } 0248 0249 TEST_CASE("Virtual Is-A") 0250 { 0251 const static char *source = 0252 R"(class C {}; 0253 class D: public virtual C {}; 0254 )"; 0255 0256 ObjectStore session; 0257 REQUIRE(Test_Util::runOnCode(session, source, "testVirtualIsA.cpp")); 0258 REQUIRE(Test_Util::isAExists("D", "C", session)); 0259 } 0260 0261 TEST_CASE("Template Is-A") 0262 { 0263 const static char *source = 0264 R"(class C {}; 0265 0266 template <typename T> 0267 class D { 0268 T t; 0269 }; 0270 0271 class E: public D<C> { 0272 }; 0273 )"; 0274 0275 ObjectStore session; 0276 REQUIRE(Test_Util::runOnCode(session, source, "testTemplateIsA.cpp")); 0277 0278 REQUIRE(Test_Util::isAExists("E", "D", session)); 0279 REQUIRE(Test_Util::usesInTheInterfaceExists("E", "C", session)); 0280 REQUIRE(!Test_Util::usesInTheImplementationExists("D", "T", session)); 0281 } 0282 0283 TEST_CASE("Template virtual Is-A") 0284 { 0285 const static char *source = 0286 R"(class C {}; 0287 0288 template <typename T> 0289 class D { 0290 T t; 0291 }; 0292 0293 class E: public virtual D<C> { 0294 }; 0295 )"; 0296 0297 ObjectStore session; 0298 REQUIRE(Test_Util::runOnCode(session, source, "testTemplateVirtualIsA.cpp")); 0299 0300 REQUIRE(Test_Util::isAExists("E", "D", session)); 0301 REQUIRE(Test_Util::usesInTheInterfaceExists("E", "C", session)); 0302 REQUIRE(!Test_Util::usesInTheImplementationExists("D", "T", session)); 0303 } 0304 0305 TEST_CASE("Uses in method arguments") 0306 { 0307 static const char *source = R"( 0308 class C {}; 0309 class D { 0310 void method(const C& c) 0311 { 0312 } 0313 }; 0314 )"; 0315 ObjectStore session; 0316 REQUIRE(Test_Util::runOnCode(session, source, "testUsesInMethodArguments.cpp")); 0317 0318 TypeObject *C = nullptr; 0319 TypeObject *D = nullptr; 0320 MethodObject *method = nullptr; 0321 0322 session.withROLock([&] { 0323 C = session.getType("C"); 0324 D = session.getType("D"); 0325 0326 method = session.getMethod("D::method", "method(const C & c)", std::string{}, "void"); 0327 }); 0328 0329 REQUIRE(D); 0330 REQUIRE(C); 0331 REQUIRE(method); 0332 0333 C->withROLock([&] { 0334 REQUIRE(C->methods().empty()); 0335 0336 // TODO: Make sure this is needed - We are not using this anywhere. 0337 /* Not implemented in LVTMDB 0338 const auto usesInMethodArgs = C->usesInMethodArguments(); 0339 REQUIRE(usesInMethodArgs.size() == 1); 0340 it = std::find(usesInMethodArgs.begin(), usesInMethodArgs.end(), method); 0341 REQUIRE(it != methods.end()); 0342 */ 0343 }); 0344 0345 D->withROLock([&] { 0346 const auto methods = D->methods(); 0347 REQUIRE(methods.size() == 1); 0348 auto it = std::find(methods.begin(), methods.end(), method); 0349 REQUIRE(it != methods.end()); 0350 0351 // TODO: Make sure this is needed. 0352 // Not Implemented in LVTMDB 0353 // REQUIRE(D->usesInMethodArguments().empty()); 0354 }); 0355 } 0356 0357 TEST_CASE("Uses in field type") 0358 { 0359 static const char *source = R"( 0360 class C {}; 0361 class D { 0362 C field; 0363 }; 0364 )"; 0365 ObjectStore session; 0366 REQUIRE(Test_Util::runOnCode(session, source, "testUsesInFieldType.cpp")); 0367 TypeObject *C = nullptr; 0368 TypeObject *D = nullptr; 0369 FieldObject *field = nullptr; 0370 0371 session.withROLock([&] { 0372 C = session.getType("C"); 0373 D = session.getType("D"); 0374 field = session.getField("D::field"); 0375 }); 0376 0377 REQUIRE(C); 0378 REQUIRE(D); 0379 REQUIRE(field); 0380 0381 D->withRWLock([&] { 0382 const auto fields = D->fields(); 0383 REQUIRE(fields.size() == 1); 0384 auto it = std::find(fields.begin(), fields.end(), field); 0385 REQUIRE(it != fields.end()); 0386 // REQUIRE(D->usesInFieldType().empty()); 0387 }); 0388 0389 C->withROLock([&] { 0390 // Not implemented yet on lvtmdb. 0391 #if 0 0392 const auto usesInFieldTypes = C->usesInFieldType(); 0393 REQUIRE(usesInFieldTypes.size() == 1); 0394 it = std::find(usesInFieldTypes.begin(), usesInFieldTypes.end(), field); 0395 REQUIRE(it != usesInFieldTypes.end()); 0396 #endif 0397 REQUIRE(C->fields().empty()); 0398 }); 0399 } 0400 0401 TEST_CASE("Uses in field array type") 0402 { 0403 static const char *source = R"( 0404 class C {}; 0405 class D { 0406 C field[3]; 0407 }; 0408 )"; 0409 ObjectStore session; 0410 REQUIRE(Test_Util::runOnCode(session, source, "testUsesInFieldType.cpp")); 0411 0412 TypeObject *C = nullptr; 0413 TypeObject *D = nullptr; 0414 FieldObject *field = nullptr; 0415 0416 session.withROLock([&] { 0417 C = session.getType("C"); 0418 D = session.getType("D"); 0419 field = session.getField("D::field"); 0420 }); 0421 0422 REQUIRE(C); 0423 REQUIRE(D); 0424 REQUIRE(field); 0425 0426 D->withRWLock([&] { 0427 const auto fields = D->fields(); 0428 REQUIRE(fields.size() == 1); 0429 auto it = std::find(fields.begin(), fields.end(), field); 0430 REQUIRE(it != fields.end()); 0431 // REQUIRE(D->usesInFieldType().empty()); 0432 }); 0433 0434 C->withROLock([&] { 0435 // Not implemented yet on lvtmdb. 0436 #if 0 0437 const auto usesInFieldTypes = C->usesInFieldType(); 0438 REQUIRE(usesInFieldTypes.size() == 1); 0439 it = std::find(usesInFieldTypes.begin(), usesInFieldTypes.end(), field); 0440 REQUIRE(it != usesInFieldTypes.end()); 0441 #endif 0442 REQUIRE(C->fields().empty()); 0443 }); 0444 0445 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0446 } 0447 0448 TEST_CASE("Class template") 0449 { 0450 static const char *source = R"( 0451 template <typename T> 0452 class C { 0453 }; 0454 0455 C<int> c; 0456 )"; 0457 ObjectStore session; 0458 REQUIRE(Test_Util::runOnCode(session, source, "testClassTemplate.cpp")); 0459 0460 session.withROLock([&] { 0461 REQUIRE(session.getType("C")); 0462 REQUIRE(session.types().size() == 1); 0463 }); 0464 0465 // check we didn't separately add C<int> 0466 } 0467 0468 TEST_CASE("Class non type template") 0469 { 0470 static const char *source = R"( 0471 template <unsigned N> 0472 class CharArray { 0473 char arr[N]; 0474 }; 0475 0476 CharArray<1> arr; 0477 )"; 0478 ObjectStore session; 0479 REQUIRE(Test_Util::runOnCode(session, source, "testClassNonTypeTemplate.cpp")); 0480 session.withROLock([&] { 0481 TypeObject *CharArray = session.getType("CharArray"); 0482 REQUIRE(CharArray); 0483 0484 // check we didn't separately add CharArray<1> 0485 REQUIRE(session.types().size() == 1); 0486 }); 0487 } 0488 0489 TEST_CASE("Class template template") 0490 { 0491 static const char *source = R"( 0492 template <class T> 0493 class C {}; 0494 0495 template <template<class> class T> 0496 class ApplyChar { 0497 T<char> t; 0498 }; 0499 0500 ApplyChar<C> a; 0501 )"; 0502 ObjectStore session; 0503 REQUIRE(Test_Util::runOnCode(session, source, "testClassTemplateTemplate.cpp")); 0504 session.withROLock([&] { 0505 REQUIRE(session.getType("C")); 0506 REQUIRE(session.getType("ApplyChar")); 0507 REQUIRE(session.types().size() == 2); 0508 }); 0509 0510 // check we didn't separately add ApplyChar<C> 0511 } 0512 0513 TEST_CASE("Type aliase namespace") 0514 { 0515 static const char *source = R"( 0516 namespace std { 0517 class Something; 0518 } 0519 0520 namespace foo { 0521 using Something = std::Something; 0522 } 0523 0524 class C { 0525 public: 0526 foo::Something& some; 0527 }; 0528 )"; 0529 ObjectStore session; 0530 REQUIRE(Test_Util::runOnCode(session, source, "testTypeAliasNamespace.cpp")); 0531 0532 NamespaceObject *foo = nullptr; 0533 TypeObject *fooSomething = nullptr; 0534 FileObject *file = nullptr; 0535 0536 session.withROLock([&] { 0537 foo = session.getNamespace("foo"); 0538 fooSomething = session.getType("foo::Something"); 0539 file = session.getFile("testTypeAliasNamespace.cpp"); 0540 }); 0541 0542 REQUIRE(fooSomething); 0543 REQUIRE(foo); 0544 REQUIRE(file); 0545 0546 fooSomething->withROLock([&] { 0547 REQUIRE(fooSomething->name() == "Something"); 0548 REQUIRE(fooSomething->kind() == UDTKind::TypeAlias); 0549 REQUIRE(fooSomething->access() == lvtshr::AccessSpecifier::e_none); 0550 REQUIRE(fooSomething->parentNamespace() == foo); 0551 REQUIRE(!fooSomething->parent()); 0552 }); 0553 0554 file->withROLock([&] { 0555 const auto udts = file->types(); 0556 const auto udts_it = std::find(udts.begin(), udts.end(), fooSomething); 0557 REQUIRE(udts_it != udts.end()); 0558 }); 0559 0560 REQUIRE(Test_Util::usesInTheImplementationExists("foo::Something", "std::Something", session)); 0561 REQUIRE(Test_Util::usesInTheInterfaceExists("C", "foo::Something", session)); 0562 } 0563 0564 TEST_CASE("enum") 0565 { 0566 static const char *source = R"( 0567 namespace foo { 0568 struct Util { 0569 enum Enum { 0570 e_ONE = 1, 0571 e_TWO, 0572 }; 0573 }; 0574 0575 enum class Byte : unsigned char {}; 0576 } 0577 )"; 0578 ObjectStore session; 0579 REQUIRE(Test_Util::runOnCode(session, source, "testEnum.cpp")); 0580 0581 TypeObject *unscoped = nullptr; 0582 TypeObject *scoped = nullptr; 0583 TypeObject *util = nullptr; 0584 FileObject *file = nullptr; 0585 NamespaceObject *foo = nullptr; 0586 0587 session.withROLock([&] { 0588 unscoped = session.getType("foo::Util::Enum"); 0589 scoped = session.getType("foo::Byte"); 0590 util = session.getType("foo::Util"); 0591 file = session.getFile("testEnum.cpp"); 0592 foo = session.getNamespace("foo"); 0593 }); 0594 0595 REQUIRE(unscoped); 0596 REQUIRE(scoped); 0597 REQUIRE(util); 0598 REQUIRE(file); 0599 REQUIRE(foo); 0600 0601 unscoped->withROLock([&] { 0602 REQUIRE(unscoped->name() == "Enum"); 0603 }); 0604 0605 scoped->withROLock([&] { 0606 REQUIRE(scoped->name() == "Byte"); 0607 }); 0608 0609 std::vector<TypeObject *> udts; 0610 file->withROLock([&] { 0611 udts = file->types(); 0612 }); 0613 0614 for (const auto& e : {unscoped, scoped}) { 0615 e->withROLock([&] { 0616 REQUIRE(e->kind() == UDTKind::Enum); 0617 const auto udts_it = std::find(udts.begin(), udts.end(), e); 0618 REQUIRE(udts_it != udts.end()); 0619 REQUIRE(e->parentNamespace() == foo); 0620 }); 0621 } 0622 0623 unscoped->withROLock([&] { 0624 REQUIRE(unscoped->parent() == util); 0625 REQUIRE(unscoped->access() == lvtshr::AccessSpecifier::e_public); 0626 }); 0627 0628 scoped->withROLock([&] { 0629 REQUIRE(!scoped->parent()); 0630 REQUIRE(scoped->access() == lvtshr::AccessSpecifier::e_none); 0631 }); 0632 } 0633 0634 TEST_CASE("Internal linkage") 0635 { 0636 static const char *source = R"( 0637 namespace { 0638 class C {}; 0639 typedef C D; 0640 0641 namespace inner { 0642 class Nested1 { 0643 class NestedSquared {}; 0644 0645 typedef class NestedSquared NS; 0646 }; 0647 0648 typedef Nested1 N; 0649 } 0650 } 0651 0652 namespace outer { 0653 namespace { 0654 class Nested2 { 0655 class NestedSquared2 {}; 0656 typedef NestedSquared2 NS2; 0657 }; 0658 0659 typedef Nested2 N2; 0660 } 0661 })"; 0662 ObjectStore session; 0663 REQUIRE(Test_Util::runOnCode(session, source, "testInternalLinkage.cpp")); 0664 0665 session.withROLock([&] { 0666 REQUIRE(session.types().empty()); 0667 }); 0668 } 0669 0670 TEST_CASE("Weird templates") 0671 { 0672 // mostly based on bdlat_typetraits.h 0673 static const char *source = R"( 0674 // baljsn_encodingstyle.h 0675 namespace baljsn { 0676 class EncodingStyle { 0677 public: 0678 enum Value { 0679 e_COMPACT = 0, 0680 e_PRETTY = 1 0681 }; 0682 0683 static int fromInt(Value *result, int number); 0684 }; 0685 } 0686 0687 template <class TYPE> 0688 struct bdlat_BasicEnumerationWrapper; 0689 0690 #define BDLAT_DECL_ENUMERATION_TRAITS(ClassName) \ 0691 template <> \ 0692 struct bdlat_BasicEnumerationWrapper<ClassName::Value> : ClassName { \ 0693 typedef ClassName Wrapper; \ 0694 }; 0695 0696 BDLAT_DECL_ENUMERATION_TRAITS(baljsn::EncodingStyle) 0697 0698 template <class TYPE> 0699 int bdlat_enumFromInt(TYPE *result, int number) 0700 { 0701 typedef typename bdlat_BasicEnumerationWrapper<TYPE>::Wrapper Wrapper; 0702 return Wrapper::fromInt(result, number); 0703 } 0704 0705 int main() 0706 { 0707 baljsn::EncodingStyle::Value style; 0708 return bdlat_enumFromInt(&style, 1); // force template instantiation 0709 } 0710 )"; 0711 ObjectStore session; 0712 REQUIRE(Test_Util::runOnCode(session, source, "testWeirdTemplates.cpp")); 0713 0714 session.withROLock([&] { 0715 auto *bad = session.getType("bdlat_BasicEnumerationWrapper<baljsn::EncodingStyle::Value>::Wrapper"); 0716 REQUIRE(!bad); 0717 }); 0718 } 0719 0720 TEST_CASE("C functions") 0721 { 0722 const static char *source = 0723 "typedef struct { int x; } Foo;" 0724 "static void g() {}" 0725 "int h(const Foo*);" 0726 "int f(Foo *foo) { g(); return h(foo); }" 0727 "int h(const Foo*) { return 42; }"; 0728 ObjectStore session; 0729 REQUIRE(Test_Util::runOnCode(session, source, "testFreeFunction.cpp")); 0730 auto obtainedFunctionNames = [&]() { 0731 auto res = std::unordered_set<std::string>{}; 0732 session.withROLock([&]() { 0733 for (auto const& [f, fd] : session.functions()) { 0734 auto& _fd = fd; 0735 fd->withROLock([&]() { 0736 res.insert(_fd->qualifiedName()); 0737 }); 0738 } 0739 }); 0740 return res; 0741 }(); 0742 { 0743 using Expected = decltype(obtainedFunctionNames); 0744 REQUIRE(obtainedFunctionNames == Expected{"f", "g", "h"}); 0745 } 0746 0747 auto obtainedFunctionsInFiles = [&]() { 0748 auto res = std::unordered_set<std::string>{}; 0749 auto *file = [&]() { 0750 auto *ret = (FileObject *) nullptr; 0751 session.withROLock([&]() { 0752 ret = session.getFile("testFreeFunction.cpp"); 0753 }); 0754 return ret; 0755 }(); 0756 file->withROLock([&]() { 0757 for (auto const& func : file->globalFunctions()) { 0758 func->withROLock([&]() { 0759 res.insert(func->qualifiedName()); 0760 }); 0761 } 0762 }); 0763 return res; 0764 }(); 0765 { 0766 using Expected = decltype(obtainedFunctionsInFiles); 0767 REQUIRE(obtainedFunctionsInFiles == Expected{"f", "g", "h"}); 0768 } 0769 }