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 }