File indexing completed on 2024-05-19 05:42:04
0001 // ct_lvtclp_testrelationships.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 general tests of codebasedbvisitor 0021 0022 #include <ct_lvtmdb_objectstore.h> 0023 0024 #include <ct_lvtclp_testutil.h> 0025 0026 #include <catch2-local-includes.h> 0027 0028 using namespace Codethink::lvtclp; 0029 using namespace Codethink::lvtmdb; 0030 0031 const PyDefaultGilReleasedContext defaultGilContextForTesting; 0032 0033 TEST_CASE("Private field") 0034 { 0035 const static char *source = 0036 R"(class C {}; 0037 class D { 0038 private: 0039 C c; 0040 }; 0041 )"; 0042 0043 ObjectStore memDb; 0044 REQUIRE(Test_Util::runOnCode(memDb, source, "testPrivateField.cpp")); 0045 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", memDb)); 0046 } 0047 0048 TEST_CASE("Public field") 0049 { 0050 const static char *source = 0051 R"(class C {}; 0052 class D { 0053 public: 0054 C c; 0055 }; 0056 )"; 0057 0058 ObjectStore memDb; 0059 REQUIRE(Test_Util::runOnCode(memDb, source, "testPrivateField.cpp")); 0060 REQUIRE(Test_Util::usesInTheInterfaceExists("D", "C", memDb)); 0061 } 0062 0063 TEST_CASE("Method in interface") 0064 { 0065 const static char *source = 0066 R"(class C; 0067 class D; 0068 class E; 0069 0070 class Foo { 0071 public: 0072 void pub(C& c) 0073 { 0074 } 0075 0076 protected: 0077 void prot(D& c) 0078 { 0079 } 0080 0081 private: 0082 void priv(E& e) 0083 { 0084 } 0085 }; 0086 )"; 0087 0088 ObjectStore session; 0089 REQUIRE(Test_Util::runOnCode(session, source, "testMethodInterface.cpp")); 0090 REQUIRE(Test_Util::usesInTheInterfaceExists("Foo", "C", session)); 0091 REQUIRE(!Test_Util::usesInTheImplementationExists("Foo", "C", session)); 0092 REQUIRE(Test_Util::usesInTheInterfaceExists("Foo", "D", session)); 0093 REQUIRE(!Test_Util::usesInTheImplementationExists("Foo", "D", session)); 0094 REQUIRE(!Test_Util::usesInTheInterfaceExists("Foo", "E", session)); 0095 REQUIRE(Test_Util::usesInTheImplementationExists("Foo", "E", session)); 0096 } 0097 0098 TEST_CASE("Method body") 0099 { 0100 { 0101 const static char *source = 0102 R"(class C {}; 0103 class D { 0104 void method() { 0105 C c; 0106 } 0107 }; 0108 )"; 0109 0110 ObjectStore session; 0111 REQUIRE(Test_Util::runOnCode(session, source, "testMethodBody.cpp")); 0112 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0113 } 0114 0115 { 0116 const static char *source = 0117 R"(class C {}; 0118 class D { 0119 void method(); 0120 }; 0121 void D::method() 0122 { 0123 C c; 0124 } 0125 )"; 0126 0127 ObjectStore session; 0128 REQUIRE(Test_Util::runOnCode(session, source, "testMethodBody2.cpp")); 0129 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0130 } 0131 } 0132 0133 TEST_CASE("Temporary object") 0134 { 0135 const static char *source = 0136 R"(class C {}; 0137 void freeFunction(C c) {} 0138 class D { 0139 void method() { 0140 freeFunction(C()); 0141 } 0142 }; 0143 )"; 0144 0145 ObjectStore session; 0146 REQUIRE(Test_Util::runOnCode(session, source, "testTemporaryObject.cpp")); 0147 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0148 } 0149 0150 TEST_CASE("Static method") 0151 { 0152 const static char *source = 0153 R"(class C { 0154 public: 0155 static void method() {} 0156 }; 0157 0158 class D { 0159 void method() 0160 { 0161 C::method(); 0162 } 0163 }; 0164 )"; 0165 0166 ObjectStore session; 0167 REQUIRE(Test_Util::runOnCode(session, source, "testStaticMethod.cpp")); 0168 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0169 } 0170 0171 TEST_CASE("Typedef") 0172 { 0173 const static char *source = 0174 R"(class C {}; 0175 typedef C CEE; 0176 class D { 0177 private: 0178 CEE c; 0179 }; 0180 )"; 0181 0182 ObjectStore session; 0183 REQUIRE(Test_Util::runOnCode(session, source, "testTypedef.cpp")); 0184 REQUIRE(Test_Util::usesInTheImplementationExists("CEE", "C", session)); 0185 REQUIRE(Test_Util::usesInTheImplementationExists("D", "CEE", session)); 0186 } 0187 0188 TEST_CASE("Using alias") 0189 { 0190 const static char *source = 0191 R"(class C {}; 0192 using CEE = C; 0193 class D { 0194 private: 0195 CEE c; 0196 }; 0197 )"; 0198 0199 ObjectStore session; 0200 REQUIRE(Test_Util::runOnCode(session, source, "testUsingAlias.cpp")); 0201 REQUIRE(Test_Util::usesInTheImplementationExists("CEE", "C", session)); 0202 REQUIRE(Test_Util::usesInTheImplementationExists("D", "CEE", session)); 0203 } 0204 0205 TEST_CASE("Template class") 0206 { 0207 const static char *source = 0208 R"(class C {}; 0209 0210 template<typename T> 0211 class D { 0212 T t; 0213 }; 0214 0215 class E { 0216 D<C> dc; 0217 }; 0218 )"; 0219 0220 ObjectStore session; 0221 REQUIRE(Test_Util::runOnCode(session, source, "testTemplateClass.cpp")); 0222 REQUIRE(Test_Util::usesInTheImplementationExists("E", "C", session)); 0223 REQUIRE(Test_Util::usesInTheImplementationExists("E", "D", session)); 0224 REQUIRE(!Test_Util::usesInTheImplementationExists("D", "C", session)); 0225 REQUIRE(!Test_Util::usesInTheImplementationExists("D", "T", session)); 0226 } 0227 0228 TEST_CASE("Template method") 0229 { 0230 const static char *source = 0231 R"(class C {}; 0232 0233 class D { 0234 public: 0235 template <typename T> 0236 static void method(T t) 0237 { 0238 C c; 0239 } 0240 }; 0241 0242 class E { 0243 public: 0244 void method() 0245 { 0246 D::method(1); 0247 } 0248 }; 0249 )"; 0250 0251 ObjectStore session; 0252 REQUIRE(Test_Util::runOnCode(session, source, "testTemplateMethod.cpp")); 0253 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0254 REQUIRE(Test_Util::usesInTheImplementationExists("E", "D", session)); 0255 } 0256 0257 TEST_CASE("Member type") 0258 { 0259 const static char *source = 0260 R"(class Pub1 {}; 0261 class Pub2 {}; 0262 class Prot1 {}; 0263 class Prot2 {}; 0264 class Priv1 {}; 0265 class Priv2 {}; 0266 0267 class C { 0268 public: 0269 using pub1 = Pub1; 0270 typedef Pub2 pub2; 0271 0272 protected: 0273 using prot1 = Prot1; 0274 typedef Prot2 prot2; 0275 0276 private: 0277 using priv1 = Priv1; 0278 typedef Priv2 priv2; 0279 }; 0280 )"; 0281 ObjectStore session; 0282 REQUIRE(Test_Util::runOnCode(session, source, "testMemberType.cpp")); 0283 REQUIRE(Test_Util::usesInTheInterfaceExists("C", "C::pub1", session)); 0284 REQUIRE(Test_Util::usesInTheInterfaceExists("C", "C::pub2", session)); 0285 REQUIRE(Test_Util::usesInTheInterfaceExists("C", "C::prot1", session)); 0286 REQUIRE(Test_Util::usesInTheInterfaceExists("C", "C::prot2", session)); 0287 REQUIRE(Test_Util::usesInTheImplementationExists("C", "C::priv1", session)); 0288 REQUIRE(Test_Util::usesInTheImplementationExists("C", "C::priv2", session)); 0289 REQUIRE(Test_Util::usesInTheImplementationExists("C::pub1", "Pub1", session)); 0290 REQUIRE(Test_Util::usesInTheImplementationExists("C::pub2", "Pub2", session)); 0291 REQUIRE(Test_Util::usesInTheImplementationExists("C::prot1", "Prot1", session)); 0292 REQUIRE(Test_Util::usesInTheImplementationExists("C::prot2", "Prot2", session)); 0293 REQUIRE(Test_Util::usesInTheImplementationExists("C::priv1", "Priv1", session)); 0294 REQUIRE(Test_Util::usesInTheImplementationExists("C::priv2", "Priv2", session)); 0295 } 0296 0297 TEST_CASE("Template member variable") 0298 { 0299 const static char *source = 0300 R"(class C {}; 0301 0302 template <typename T> 0303 class D { 0304 public: 0305 void method() 0306 { 0307 T var; 0308 } 0309 }; 0310 0311 class E { 0312 D<C> d; 0313 0314 void method() 0315 { 0316 d.method(); 0317 } 0318 }; 0319 )"; 0320 0321 ObjectStore session; 0322 REQUIRE(Test_Util::runOnCode(session, source, "testTemplateMemberVar.cpp")); 0323 0324 // we want to make sure the template instantiation doesn't cause a spurious 0325 // D -> C relation 0326 // (regression test) 0327 REQUIRE(!Test_Util::usesInTheImplementationExists("D", "C", session)); 0328 REQUIRE(Test_Util::usesInTheImplementationExists("E", "C", session)); 0329 REQUIRE(Test_Util::usesInTheImplementationExists("E", "D", session)); 0330 } 0331 0332 TEST_CASE("Template member variable 2") 0333 { 0334 const static char *source = 0335 R"(class C {}; 0336 0337 class D { 0338 public: 0339 template <typename T> 0340 void method() 0341 { 0342 T var; 0343 } 0344 }; 0345 0346 class E { 0347 D d; 0348 0349 void method() 0350 { 0351 d.method<C>(); 0352 } 0353 }; 0354 )"; 0355 ObjectStore session; 0356 REQUIRE(Test_Util::runOnCode(session, source, "testTemplateMemberVar2.cpp")); 0357 0358 // we want to make sure the template instantiation doesn't cause a spurious 0359 // D -> C relation 0360 // (regression test) 0361 REQUIRE(!Test_Util::usesInTheImplementationExists("D", "C", session)); 0362 REQUIRE(Test_Util::usesInTheImplementationExists("E", "C", session)); 0363 REQUIRE(Test_Util::usesInTheImplementationExists("E", "D", session)); 0364 } 0365 0366 TEST_CASE("Template non template variable") 0367 { 0368 const static char *source = 0369 R"(class C {}; 0370 class D {}; 0371 0372 template <typename T> 0373 class E { 0374 public: 0375 void method() 0376 { 0377 T a; 0378 D b; 0379 } 0380 }; 0381 0382 class F { 0383 E<C> e; 0384 0385 void method() 0386 { 0387 e.method(); 0388 } 0389 }; 0390 )"; 0391 0392 ObjectStore session; 0393 REQUIRE(Test_Util::runOnCode(session, source, "testTemplateNonTemplateVar.cpp")); 0394 REQUIRE(Test_Util::usesInTheImplementationExists("E", "D", session)); 0395 REQUIRE(Test_Util::usesInTheImplementationExists("F", "E", session)); 0396 REQUIRE(Test_Util::usesInTheImplementationExists("F", "C", session)); 0397 } 0398 0399 TEST_CASE("Weird template specialization") 0400 { 0401 // based on BDLAT_DECL_ENUMERATION_TRAITS 0402 // in bdlat_typetraits.h 0403 const static char *source = 0404 R"(class C {}; 0405 0406 template <typename T> 0407 struct S {}; 0408 0409 template <> 0410 struct S<C> : C { 0411 typedef C Wrapper; 0412 }; 0413 )"; 0414 0415 ObjectStore session; 0416 REQUIRE(Test_Util::runOnCode(session, source, "testWeirdTemplateSpecialization.cpp")); 0417 REQUIRE(!Test_Util::usesInTheImplementationExists("S", "C", session)); 0418 REQUIRE(!Test_Util::isAExists("S", "C", session)); 0419 } 0420 0421 TEST_CASE("Template typedef") 0422 { 0423 // Make sure that fixes for testWeirdTemplateSpecialization 0424 // don't break other things 0425 const static char *source = 0426 R"(class C {}; 0427 class D {}; 0428 0429 template <typename T> 0430 class E { 0431 public: 0432 typedef D foo; 0433 }; 0434 0435 class F { 0436 E<C> d; 0437 }; 0438 )"; 0439 0440 ObjectStore session; 0441 REQUIRE(Test_Util::runOnCode(session, source, "testTemplateTypedef.cpp")); 0442 REQUIRE(!Test_Util::usesInTheInterfaceExists("E", "C", session)); 0443 REQUIRE(!Test_Util::usesInTheImplementationExists("E", "C", session)); 0444 REQUIRE(Test_Util::usesInTheInterfaceExists("E", "E::foo", session)); 0445 REQUIRE(Test_Util::usesInTheImplementationExists("E::foo", "D", session)); 0446 REQUIRE(Test_Util::usesInTheImplementationExists("F", "E", session)); 0447 REQUIRE(Test_Util::usesInTheImplementationExists("F", "C", session)); 0448 } 0449 0450 TEST_CASE("Template field") 0451 { 0452 const static char *source = 0453 R"(class C {}; 0454 0455 template <typename T> 0456 class D {}; 0457 0458 template <typename TYPE> 0459 class E { 0460 D<TYPE> d; 0461 }; 0462 0463 template <> 0464 class E<C>; 0465 )"; 0466 ObjectStore session; 0467 REQUIRE(Test_Util::runOnCode(session, source, "testTemplateField.cpp")); 0468 REQUIRE(Test_Util::usesInTheImplementationExists("E", "D", session)); 0469 } 0470 0471 TEST_CASE("Static field in method") 0472 { 0473 const static char *source = R"( 0474 class C { 0475 public: 0476 static constexpr int i = 0; 0477 }; 0478 0479 class D { 0480 void method() 0481 { 0482 int local = C::i; 0483 } 0484 }; 0485 )"; 0486 ObjectStore session; 0487 REQUIRE(Test_Util::runOnCode(session, source, "testStaticFieldInMethod.cpp")); 0488 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0489 } 0490 0491 TEST_CASE("Static reference in static field") 0492 { 0493 const static char *source = R"( 0494 class Zero { 0495 public: 0496 static constexpr int val = 0; 0497 }; 0498 0499 class One { 0500 public: 0501 static constexpr int val() 0502 { 0503 return 1; 0504 } 0505 }; 0506 0507 class C { 0508 private: 0509 static constexpr int zero = Zero::val; 0510 0511 public: 0512 static constexpr int one = One::val(); 0513 }; 0514 )"; 0515 ObjectStore session; 0516 REQUIRE(Test_Util::runOnCode(session, source, "testStaticRefInStaticField.cpp")); 0517 REQUIRE(Test_Util::usesInTheImplementationExists("C", "Zero", session)); 0518 REQUIRE(Test_Util::usesInTheImplementationExists("C", "One", session)); 0519 } 0520 0521 TEST_CASE("Static reference in field") 0522 { 0523 const static char *source = R"( 0524 class Zero { 0525 public: 0526 static constexpr int val = 0; 0527 }; 0528 0529 class One { 0530 public: 0531 static constexpr int val() 0532 { 0533 return 1; 0534 } 0535 }; 0536 0537 class C { 0538 private: 0539 int zero = Zero::val; 0540 0541 public: 0542 int one = One::val(); 0543 }; 0544 )"; 0545 ObjectStore session; 0546 REQUIRE(Test_Util::runOnCode(session, source, "testStaticRefInField.cpp")); 0547 0548 REQUIRE(Test_Util::usesInTheImplementationExists("C", "Zero", session)); 0549 REQUIRE(Test_Util::usesInTheImplementationExists("C", "One", session)); 0550 } 0551 0552 TEST_CASE("Call expr in field") 0553 { 0554 const static char *source = R"( 0555 class C; 0556 0557 template<class T> 0558 bool templateFn(); 0559 0560 class D { 0561 bool field = templateFn<C>(); 0562 }; 0563 )"; 0564 ObjectStore session; 0565 REQUIRE(Test_Util::runOnCode(session, source, "testCallExprInField.cpp")); 0566 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0567 } 0568 0569 TEST_CASE("Method return") 0570 { 0571 const static char *source = R"( 0572 class C {}; 0573 class D {}; 0574 class E {}; 0575 0576 class F { 0577 public: 0578 C methodC() { return C(); } 0579 static D methodD() { return D(); } 0580 0581 private: 0582 E methodE() { return E(); } 0583 }; 0584 )"; 0585 ObjectStore session; 0586 REQUIRE(Test_Util::runOnCode(session, source, "testMethodReturn.cpp")); 0587 0588 REQUIRE(Test_Util::usesInTheInterfaceExists("F", "C", session)); 0589 REQUIRE(Test_Util::usesInTheInterfaceExists("F", "D", session)); 0590 REQUIRE(!Test_Util::usesInTheInterfaceExists("F", "E", session)); 0591 REQUIRE(Test_Util::usesInTheImplementationExists("F", "C", session)); 0592 REQUIRE(Test_Util::usesInTheImplementationExists("F", "D", session)); 0593 REQUIRE(Test_Util::usesInTheImplementationExists("F", "E", session)); 0594 } 0595 0596 TEST_CASE("Lambda return") 0597 { 0598 const static char *source = R"( 0599 class C {}; 0600 class D { public: D(int i) {} }; 0601 0602 class E { 0603 public: 0604 static constexpr auto lambdaC = []() { return C(); }; 0605 static constexpr auto lambdaD = []() -> D { return 1; }; 0606 }; 0607 )"; 0608 ObjectStore session; 0609 REQUIRE(Test_Util::runOnCode(session, source, "testLambdaReturn.cpp")); 0610 0611 REQUIRE(Test_Util::usesInTheInterfaceExists("E", "C", session)); 0612 REQUIRE(Test_Util::usesInTheInterfaceExists("E", "D", session)); 0613 REQUIRE(Test_Util::usesInTheImplementationExists("E", "C", session)); 0614 // E doesn't use D in its implementation (we don't pick up the implicit cast) 0615 } 0616 0617 TEST_CASE("Template method return") 0618 { 0619 const static char *source = R"( 0620 template <typename T> 0621 class C {}; 0622 class D {}; 0623 0624 class T {}; 0625 0626 class E { 0627 public: 0628 template <typename T> 0629 C<T> method() 0630 { 0631 return C<T>(); 0632 } 0633 }; 0634 0635 class F { 0636 public: 0637 C<D> method() 0638 { 0639 E e; 0640 return e.method<D>(); 0641 } 0642 }; 0643 )"; 0644 ObjectStore session; 0645 REQUIRE(Test_Util::runOnCode(session, source, "testTempalteMethodReturn.cpp")); 0646 REQUIRE(Test_Util::usesInTheInterfaceExists("E", "C", session)); 0647 REQUIRE(!Test_Util::usesInTheInterfaceExists("E", "T", session)); 0648 REQUIRE(!Test_Util::usesInTheInterfaceExists("E", "D", session)); 0649 REQUIRE(!Test_Util::usesInTheImplementationExists("E", "T", session)); 0650 REQUIRE(Test_Util::usesInTheImplementationExists("E", "C", session)); 0651 REQUIRE(Test_Util::usesInTheInterfaceExists("F", "C", session)); 0652 REQUIRE(Test_Util::usesInTheInterfaceExists("F", "D", session)); 0653 REQUIRE(Test_Util::usesInTheImplementationExists("F", "E", session)); 0654 REQUIRE(Test_Util::usesInTheImplementationExists("F", "D", session)); 0655 } 0656 0657 TEST_CASE("Template method qualified return") 0658 { 0659 const static char *source = R"( 0660 template <typename T> 0661 class C {}; 0662 class D {}; 0663 0664 class T {}; 0665 0666 class E { 0667 public: 0668 template <typename T> 0669 const C<T> method() 0670 { 0671 return C<T>(); 0672 } 0673 }; 0674 0675 class F { 0676 public: 0677 const C<D> method() 0678 { 0679 E e; 0680 return e.method<D>(); 0681 } 0682 }; 0683 )"; 0684 ObjectStore session; 0685 REQUIRE(Test_Util::runOnCode(session, source, "testTempalteMethodQualifiedReturn.cpp")); 0686 0687 REQUIRE(Test_Util::usesInTheInterfaceExists("E", "C", session)); 0688 REQUIRE(!Test_Util::usesInTheInterfaceExists("E", "T", session)); 0689 REQUIRE(!Test_Util::usesInTheInterfaceExists("E", "D", session)); 0690 REQUIRE(!Test_Util::usesInTheImplementationExists("E", "T", session)); 0691 REQUIRE(Test_Util::usesInTheImplementationExists("E", "C", session)); 0692 REQUIRE(Test_Util::usesInTheInterfaceExists("F", "C", session)); 0693 REQUIRE(Test_Util::usesInTheInterfaceExists("F", "D", session)); 0694 REQUIRE(Test_Util::usesInTheImplementationExists("F", "E", session)); 0695 REQUIRE(Test_Util::usesInTheImplementationExists("F", "D", session)); 0696 } 0697 0698 TEST_CASE("Template qualified field") 0699 { 0700 const static char *source = 0701 R"(class C {}; 0702 0703 template <typename T> 0704 class D {}; 0705 0706 template <typename TYPE> 0707 class E { 0708 volatile D<TYPE> d; 0709 }; 0710 0711 template <> 0712 class E<C>; 0713 )"; 0714 ObjectStore session; 0715 0716 REQUIRE(Test_Util::runOnCode(session, source, "testTemplateQualifiedField.cpp")); 0717 REQUIRE(Test_Util::usesInTheImplementationExists("E", "D", session)); 0718 } 0719 0720 TEST_CASE("Method arg template specialization") 0721 { 0722 const static char *source = R"( 0723 class C; 0724 0725 template<typename T> 0726 struct hash { 0727 int operator()(const T& t) const noexcept; 0728 }; 0729 0730 template<> 0731 struct hash<C> { 0732 int operator()(const C& c) const noexcept 0733 { 0734 return 0; 0735 } 0736 }; 0737 )"; 0738 ObjectStore session; 0739 REQUIRE(Test_Util::runOnCode(session, source, "testMethodArgTemplateSpecialization.cpp")); 0740 REQUIRE(!Test_Util::usesInTheInterfaceExists("hash", "C", session)); 0741 REQUIRE(!Test_Util::usesInTheImplementationExists("hash", "C", session)); 0742 } 0743 0744 TEST_CASE("Static method template specialization") 0745 { 0746 const static char *source = R"( 0747 class C {}; 0748 0749 template<typename T> 0750 class numeric_limits { 0751 static T quiet_NaN() noexcept; 0752 }; 0753 0754 template<> 0755 class numeric_limits<C> { 0756 static C quiet_NaN() noexcept; 0757 }; 0758 0759 C numeric_limits<C>::quiet_NaN() noexcept 0760 { 0761 return C(); 0762 } 0763 )"; 0764 ObjectStore session; 0765 REQUIRE(Test_Util::runOnCode(session, source, "testStaticMethodTemplateSpecialization.cpp")); 0766 REQUIRE(!Test_Util::usesInTheInterfaceExists("numeric_limits", "C", session)); 0767 REQUIRE(!Test_Util::usesInTheImplementationExists("numeric_limits", "C", session)); 0768 } 0769 0770 TEST_CASE("Typedef template") 0771 { 0772 const static char *source = R"( 0773 template <typename T> 0774 class C; 0775 0776 template <typename T> 0777 class Foo {}; 0778 0779 template <typename T> 0780 class Foo<C<T>> { 0781 public: 0782 typedef C<T> Type; 0783 }; 0784 )"; 0785 ObjectStore session; 0786 REQUIRE(Test_Util::runOnCode(session, source, "testTypedefTemplate.cpp")); 0787 REQUIRE(!Test_Util::usesInTheInterfaceExists("Foo", "C", session)); 0788 } 0789 0790 TEST_CASE("Default argument") 0791 { 0792 const static char *source = R"( 0793 class C { 0794 public: 0795 operator char() 0796 { 0797 return 'C'; 0798 } 0799 }; 0800 0801 class D { 0802 public: 0803 void method(char c = C()) 0804 { 0805 } 0806 }; 0807 )"; 0808 ObjectStore session; 0809 REQUIRE(Test_Util::runOnCode(session, source, "testDefaultArgument.cpp")); 0810 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0811 REQUIRE(!Test_Util::usesInTheInterfaceExists("D", "C", session)); 0812 } 0813 0814 TEST_CASE("Decltype") 0815 { 0816 // Check that we resolve decltype() when doing a type lookup 0817 const static char *source = R"( 0818 class C {}; 0819 0820 class D { 0821 public: 0822 static C getC(); 0823 }; 0824 0825 class E { 0826 public: 0827 decltype(D::getC()) method() 0828 { 0829 return D::getC(); 0830 } 0831 }; 0832 )"; 0833 ObjectStore session; 0834 REQUIRE(Test_Util::runOnCode(session, source, "testDecltype.cpp")); 0835 0836 REQUIRE(Test_Util::usesInTheInterfaceExists("E", "C", session)); 0837 REQUIRE(Test_Util::usesInTheImplementationExists("E", "D", session)); 0838 } 0839 0840 TEST_CASE("Dependent decltype") 0841 { 0842 // Check that we resolve decltype() when doing a type lookup 0843 const static char *source = R"( 0844 template <class TYPE> 0845 class C {}; 0846 0847 template <class TYPE> 0848 class D { 0849 public: 0850 static C<TYPE> getC(); 0851 }; 0852 0853 template <class TYPE> 0854 class E { 0855 public: 0856 decltype(D<TYPE>::getC()) method() 0857 { 0858 return D<TYPE>::getC(); 0859 } 0860 }; 0861 )"; 0862 ObjectStore session; 0863 REQUIRE(Test_Util::runOnCode(session, source, "testDependentDecltype.cpp")); 0864 0865 // While it would be great to be able to infer E -> C, this isn't possible 0866 // in general because the type resulting from the expression could change 0867 // arbitrarily depending upon template specializations. In this example, there 0868 // could be a specialization for D<int> which returns bool from getC(); 0869 // Therefore clang correctly refuses to resolve the type of a dependent 0870 // decltype expression. 0871 // 0872 // E -> D tests CXXDependentScopeMemberExpr in 0873 // CodebaseDbVisitor::processChildStatements 0874 REQUIRE(!Test_Util::usesInTheInterfaceExists("E", "C", session)); 0875 REQUIRE(Test_Util::usesInTheImplementationExists("E", "D", session)); 0876 } 0877 0878 TEST_CASE("Using false positive") 0879 { 0880 const static char *source = R"( 0881 namespace foo { 0882 class C; 0883 } 0884 0885 using foo::C; 0886 )"; 0887 ObjectStore session; 0888 REQUIRE(Test_Util::runOnCode(session, source, "testUsingFalsePositive.cpp")); 0889 0890 // make sure we didn't add ::C as an alias at file scope 0891 session.withROLock([&] { 0892 REQUIRE(!session.getType("C")); 0893 }); 0894 } 0895 0896 TEST_CASE("Re-exported type") 0897 { 0898 // based on bslstl_iterator and bslstl_vector 0899 const static char *source = R"( 0900 namespace native_std { 0901 template <class ITER> 0902 class reverse_iterator; 0903 } 0904 0905 namespace bsl { 0906 using native_std::reverse_iterator; 0907 0908 template <class VALUE_TYPE> 0909 class vectorBase { 0910 public: 0911 typedef VALUE_TYPE *iterator; 0912 typedef bsl::reverse_iterator<iterator> reverse_iterator; 0913 }; 0914 } 0915 )"; 0916 ObjectStore session; 0917 REQUIRE(Test_Util::runOnCode(session, source, "testReExportedType.cpp")); 0918 REQUIRE(Test_Util::usesInTheImplementationExists("bsl::reverse_iterator", "native_std::reverse_iterator", session)); 0919 REQUIRE(Test_Util::usesInTheImplementationExists("bsl::vectorBase::reverse_iterator", 0920 "bsl::reverse_iterator", 0921 session)); 0922 } 0923 0924 TEST_CASE("Const typename") 0925 { 0926 // based on bsls_atomicoperations_default 0927 const static char *source = R"( 0928 struct AtomicTypes { 0929 typedef void * Pointer; 0930 }; 0931 0932 class C { 0933 public: 0934 void method(typename AtomicTypes::Pointer const *ptrPtr); 0935 }; 0936 )"; 0937 ObjectStore session; 0938 REQUIRE(Test_Util::runOnCode(session, source, "testConstTypename.cpp")); 0939 REQUIRE(Test_Util::usesInTheInterfaceExists("C", "AtomicTypes::Pointer", session)); 0940 } 0941 0942 TEST_CASE("Double pointer to builtin") 0943 { 0944 // Unfortunately I can't think of a way of observing in the database if we 0945 // did the right or the wrong thing here. 0946 // The engineer has to manually review output to check there are no WARN 0947 // messages about failed lookups 0948 static const char *source = R"( 0949 class C { 0950 void method(void **ptr); 0951 void method2(void *array[2]); 0952 }; 0953 )"; 0954 ObjectStore session; 0955 REQUIRE(Test_Util::runOnCode(session, source, "testDoublePointerToBuiltin.cpp")); 0956 } 0957 0958 TEST_CASE("Atomic type") 0959 { 0960 // based on bsls_buildtarget 0961 static const char *source = R"( 0962 struct Types { 0963 typedef long long Int64; 0964 }; 0965 0966 struct AtomicInt { 0967 _Atomic(int) d_value; 0968 }; 0969 0970 struct AtomicInt64 { 0971 _Atomic(Types::Int64) d_value; 0972 }; 0973 )"; 0974 ObjectStore session; 0975 REQUIRE(Test_Util::runOnCode(session, source, "testAtomicType.cpp")); 0976 REQUIRE(Test_Util::usesInTheInterfaceExists("AtomicInt64", "Types::Int64", session)); 0977 } 0978 0979 TEST_CASE("Forward declt type lookup") 0980 { 0981 // the interesting thing is that clang says the type is called 0982 // "bsls::struct Types::Int64" 0983 static const char *source = R"( 0984 namespace bsls { 0985 struct Types { 0986 typedef long long Int64; 0987 }; 0988 } 0989 0990 class C { 0991 public: 0992 void method(bsls::Types::Int64 arg); 0993 }; 0994 )"; 0995 ObjectStore session; 0996 REQUIRE(Test_Util::runOnCode(session, source, "testForwardDeclTypeLookup.cpp")); 0997 REQUIRE(Test_Util::usesInTheInterfaceExists("C", "bsls::Types::Int64", session)); 0998 } 0999 1000 TEST_CASE("Fully qualified name lookup") 1001 { 1002 // sometimes clang prints types only partially qualified, leading to database 1003 // lookup failure: e.g. in this case it looks up "Types::Int64" not 1004 // "bsls::Types::Int64". Check that we correct this. 1005 static const char *source = R"( 1006 namespace bsls { 1007 struct Types { 1008 typedef long long Int64; 1009 }; 1010 1011 class C { 1012 public: 1013 void method(Types::Int64 arg); 1014 }; 1015 } 1016 )"; 1017 ObjectStore session; 1018 REQUIRE(Test_Util::runOnCode(session, source, "testFullyQualifiedNameLookup.cpp")); 1019 REQUIRE(Test_Util::usesInTheInterfaceExists("bsls::C", "bsls::Types::Int64", session)); 1020 } 1021 1022 TEST_CASE("Buildint type array") 1023 { 1024 static const char *source = R"( 1025 class C { 1026 static const char string[]; 1027 }; 1028 )"; 1029 ObjectStore session; 1030 REQUIRE(Test_Util::runOnCode(session, source, "testBuiltInTypeArray.cpp")); 1031 // Unfortunately have to manually check for the failed lookup WARN messsage 1032 } 1033 1034 TEST_CASE("Const ref typedef") 1035 { 1036 static const char *source = R"( 1037 namespace bslmt { 1038 1039 // bslmt_platform.h 1040 struct Platform { 1041 struct PosixThreads {}; 1042 typedef PosixThreads ThreadPolicy; 1043 }; 1044 1045 // bslmt_threadutilimpl_pthread.h 1046 1047 template <class THREAD_POLICY> 1048 struct ThreadUtilImpl; 1049 1050 template <> 1051 struct ThreadUtilImpl<Platform::PosixThreads> { 1052 typedef int Handle; 1053 }; 1054 1055 // bslmt_threadutil.h 1056 struct ThreadUtil { 1057 typedef ThreadUtilImpl<Platform::ThreadPolicy> Imp; 1058 typedef Imp::Handle Handle; 1059 1060 void method(const Handle&); 1061 }; 1062 } 1063 )"; 1064 ObjectStore session; 1065 REQUIRE(Test_Util::runOnCode(session, source, "testConstRefTypedef.cpp")); 1066 REQUIRE(Test_Util::usesInTheInterfaceExists("bslmt::ThreadUtil", "bslmt::ThreadUtil::Handle", session)); 1067 } 1068 1069 TEST_CASE("Bsls atomic operations") 1070 { 1071 // bsls::AtomicTypes has been a repeated pain point when dealing with lookup 1072 // failures. Check we do the right thing 1073 static const char *source = R"( 1074 namespace bsls { 1075 1076 // bsls_atomicoperations_default.h 1077 template <class IMP> 1078 struct Atomic_TypeTraits; 1079 1080 template <class IMP> 1081 struct AtomicOperations_DefaultInt { 1082 public: 1083 typedef Atomic_TypeTraits<IMP> AtomicTypes; 1084 1085 private: 1086 // Tricky lookup is here: 1087 static int getInt(typename AtomicTypes::Int const *atomicInt); 1088 }; 1089 1090 // bsls_atomicoperations_all_all_clangintrinsics.h 1091 struct AtomicOperations_ALL_ALL_ClangIntrinsics; 1092 typedef AtomicOperations_ALL_ALL_ClangIntrinsics AtomicOperations_Imp; 1093 1094 template <> 1095 struct Atomic_TypeTraits<AtomicOperations_ALL_ALL_ClangIntrinsics> 1096 { 1097 struct __attribute((__aligned__(sizeof(int)))) Int 1098 { 1099 _Atomic(int) d_value; 1100 }; 1101 }; 1102 1103 struct AtomicOperations_ALL_ALL_ClangIntrinsics 1104 : AtomicOperations_DefaultInt<AtomicOperations_ALL_ALL_ClangIntrinsics> 1105 { 1106 typedef Atomic_TypeTraits<AtomicOperations_ALL_ALL_ClangIntrinsics> 1107 AtomicTypes; 1108 1109 static int getInt(const AtomicTypes::Int *atomicInt); 1110 }; 1111 1112 // bsls_atomicoperations.h 1113 struct AtomicOperations { 1114 typedef AtomicOperations_Imp Imp; 1115 typedef Atomic_TypeTraits<Imp> AtomicTypes; 1116 1117 static int getInt(AtomicTypes::Int const *atomicInt); 1118 }; 1119 1120 } 1121 )"; 1122 ObjectStore session; 1123 REQUIRE(Test_Util::runOnCode(session, source, "testBslsAtomicOperations.cpp")); 1124 1125 REQUIRE(Test_Util::usesInTheImplementationExists("bsls::AtomicOperations_ALL_ALL_ClangIntrinsics::AtomicTypes", 1126 "bsls::Atomic_TypeTraits", 1127 session)); 1128 REQUIRE(Test_Util::usesInTheInterfaceExists("bsls::AtomicOperations_ALL_ALL_ClangIntrinsics", 1129 "bsls::AtomicOperations_ALL_ALL_ClangIntrinsics::AtomicTypes", 1130 session)); 1131 REQUIRE( 1132 Test_Util::usesInTheImplementationExists("bsls::AtomicOperations::Imp", "bsls::AtomicOperations_Imp", session)); 1133 REQUIRE(Test_Util::usesInTheInterfaceExists("bsls::AtomicOperations", "bsls::AtomicOperations::Imp", session)); 1134 REQUIRE(Test_Util::usesInTheImplementationExists("bsls::AtomicOperations::AtomicTypes", 1135 "bsls::Atomic_TypeTraits", 1136 session)); 1137 REQUIRE( 1138 Test_Util::usesInTheInterfaceExists("bsls::AtomicOperations", "bsls::AtomicOperations::AtomicTypes", session)); 1139 } 1140 1141 TEST_CASE("Local type alias") 1142 { 1143 // check we don't add local type aliases to the global namespace 1144 static const char *source = R"( 1145 struct RealType; 1146 1147 class C { 1148 void method() 1149 { 1150 typedef RealType TypedefType; 1151 using UsingType = RealType; 1152 1153 TypedefType *foo; 1154 UsingType *bar; 1155 } 1156 }; 1157 )"; 1158 ObjectStore session; 1159 REQUIRE(Test_Util::runOnCode(session, source, "testLocalTypeAlias.cpp")); 1160 1161 session.withROLock([&] { 1162 REQUIRE(!session.getType("TypedefType")); 1163 REQUIRE(!session.getType("UsingType")); 1164 REQUIRE(Test_Util::usesInTheImplementationExists("C", "RealType", session)); 1165 }); 1166 } 1167 1168 TEST_CASE("Allocator traits") 1169 { 1170 ObjectStore session; 1171 static const char *allocTraitSrc = R"( 1172 namespace bslma { 1173 template <class ALLOCATOR_TYPE> 1174 struct AllocatorTraits_SomeTrait { 1175 static const bool value = false; 1176 }; 1177 } 1178 )"; 1179 REQUIRE(Test_Util::runOnCode(session, allocTraitSrc, "bsl/bslma/bslma_allocatortraits.cpp")); 1180 1181 static const char *foobarSrc = R"( 1182 namespace foobar { 1183 class C {}; 1184 } 1185 1186 namespace bslma { 1187 template <class ALLOCATOR_TYPE> 1188 struct AllocatorTraits_SomeTrait; 1189 1190 template<> 1191 struct AllocatorTraits_SomeTrait<foobar::C> { 1192 static const bool value = true; 1193 }; 1194 } 1195 )"; 1196 REQUIRE(Test_Util::runOnCode(session, foobarSrc, "foo/foobar/foobar_c.cpp")); 1197 1198 REQUIRE(!Test_Util::usesInTheImplementationExists("foobar::C", "bslma::AllocatorTraits_SomeTrait", session)); 1199 REQUIRE(!Test_Util::usesInTheInterfaceExists("foobar::C", "bslma::AllocatorTraits_SomeTrait", session)); 1200 REQUIRE(!Test_Util::usesInTheImplementationExists("bslma::AllocatorTraits_SomeTrait", "foobar::C", session)); 1201 REQUIRE(!Test_Util::usesInTheInterfaceExists("bslma::AllocatorTraits_SomeTrait", "foobar::C", session)); 1202 }