File indexing completed on 2024-05-19 05:42:04

0001 // ct_lvtclp_testfunction.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 for tests for VisitFunctionDecl and VisitCXXMethodDecl
0021 
0022 #include <ct_lvtmdb_functionobject.h>
0023 #include <ct_lvtmdb_methodobject.h>
0024 #include <ct_lvtmdb_namespaceobject.h>
0025 #include <ct_lvtmdb_objectstore.h>
0026 #include <ct_lvtmdb_typeobject.h>
0027 
0028 #include <ct_lvtshr_graphenums.h>
0029 
0030 #include <ct_lvtclp_testutil.h>
0031 
0032 #include <initializer_list>
0033 #include <iostream>
0034 
0035 #include <catch2-local-includes.h>
0036 #include <clang/Basic/Version.h>
0037 
0038 using namespace Codethink::lvtclp;
0039 using namespace Codethink::lvtmdb;
0040 using namespace Codethink;
0041 
0042 const PyDefaultGilReleasedContext defaultGilContextForTesting;
0043 
0044 TEST_CASE("Function declaration")
0045 {
0046     const static char *source = R"(
0047 namespace foo {
0048 
0049 int function(int arg0, const int& arg1)
0050 {
0051     if (arg0)
0052         return arg1;
0053     return -arg1;
0054 }
0055 
0056 }
0057 )";
0058 
0059     ObjectStore session;
0060     REQUIRE(Test_Util::runOnCode(session, source, "testFunctionDecl.cpp"));
0061 
0062     NamespaceObject *foo;
0063     FunctionObject *fn = nullptr;
0064 
0065     session.withROLock([&] {
0066         foo = session.getNamespace("foo");
0067         fn = session.getFunction("foo::function", "function(int arg0, const int & arg1)", std::string{}, "int");
0068     });
0069 
0070     REQUIRE(foo);
0071     REQUIRE(fn);
0072 
0073     fn->withROLock([&] {
0074         REQUIRE(fn->name() == "function");
0075         REQUIRE(fn->signature() == "function(int arg0, const int & arg1)");
0076         REQUIRE(fn->returnType() == "int");
0077         REQUIRE(fn->templateParameters().empty());
0078         REQUIRE(fn->parent() == foo);
0079     });
0080 }
0081 
0082 TEST_CASE("Static function")
0083 {
0084     const static char *source = R"(
0085 static void function()
0086 {
0087 }
0088 )";
0089     ObjectStore session;
0090     REQUIRE(Test_Util::runOnCode(session, source, "testStaticFn.cpp"));
0091 
0092     session.withROLock([&] {
0093         REQUIRE(session.functions().size() == 1);
0094     });
0095 }
0096 
0097 TEST_CASE("Function overload")
0098 {
0099     const static char *source = R"(
0100 int foo()
0101 {
0102     return 2;
0103 }
0104 
0105 int foo(int arg)
0106 {
0107     return arg;
0108 }
0109 )";
0110     ObjectStore session;
0111     REQUIRE(Test_Util::runOnCode(session, source, "testFuncOverload.cpp"));
0112     FunctionObject *foo0 = nullptr;
0113     FunctionObject *foo1 = nullptr;
0114 
0115     session.withROLock([&] {
0116         foo0 = session.getFunction("foo", "foo()", std::string{}, "int");
0117         foo1 = session.getFunction("foo", "foo(int arg)", std::string{}, "int");
0118     });
0119 
0120     REQUIRE(foo0);
0121     REQUIRE(foo1);
0122 
0123     for (const auto& fn : {foo0, foo1}) {
0124         auto lock = fn->readOnlyLock();
0125         REQUIRE(fn->qualifiedName() == "foo");
0126         REQUIRE(fn->returnType() == "int");
0127         REQUIRE(fn->templateParameters().empty());
0128         REQUIRE(!fn->parent());
0129     }
0130 }
0131 
0132 TEST_CASE("Function forward declaration")
0133 {
0134     const static char *source = R"(
0135 void function();
0136 
0137 void function()
0138 {
0139 }
0140 )";
0141 
0142     ObjectStore session;
0143     REQUIRE(Test_Util::runOnCode(session, source, "testFnForwardDecl.cpp"));
0144 
0145     session.withROLock([&] {
0146         // REQUIRE(session.getFunction("function"));
0147         // REQUIRE(func);
0148 
0149         // check we didn't add any kind of second function for the forward decl
0150         REQUIRE(session.functions().size() == 1);
0151     });
0152 }
0153 
0154 TEST_CASE("Function template")
0155 {
0156     const static char *source = R"(
0157 template <typename T>
0158 T clone(const T& t)
0159 {
0160     return t;
0161 }
0162 
0163 void instantiateSpecialization()
0164 {
0165     int i = 2;
0166     int j = clone(i);
0167     int k = clone<int>(i);
0168 }
0169 )";
0170     ObjectStore session;
0171     REQUIRE(Test_Util::runOnCode(session, source, "testFnTemplate.cpp"));
0172 
0173     FunctionObject *clone = nullptr;
0174     session.withROLock([&] {
0175         clone = session.getFunction("clone", "clone(const T & t)", "template <typename T>", "type-parameter-0-0");
0176 
0177         // check we didn't separately add clone<int>
0178         REQUIRE(session.functions().size() == 2);
0179     });
0180 
0181     REQUIRE(clone);
0182 
0183     clone->withROLock([&] {
0184         REQUIRE(clone->templateParameters() == "template <typename T>");
0185     });
0186 }
0187 
0188 TEST_CASE("Function default parameters")
0189 {
0190     const static char *source = R"(
0191 namespace foo {
0192 
0193 int function(int &arg1, const int arg0 = 0)
0194 {
0195     if (arg0)
0196         return arg1;
0197     return -arg1;
0198 }
0199 
0200 }
0201 )";
0202     ObjectStore session;
0203     REQUIRE(Test_Util::runOnCode(session, source, "testFnDefaultParams.cpp"));
0204 
0205     NamespaceObject *foo = nullptr;
0206     FunctionObject *fn = nullptr;
0207     session.withROLock([&] {
0208         foo = session.getNamespace("foo");
0209         fn = session.getFunction("foo::function", "function(int & arg1, const int arg0 = 0)", std::string{}, "int");
0210     });
0211 
0212     REQUIRE(foo);
0213     REQUIRE(fn);
0214 
0215     fn->withROLock([&] {
0216         REQUIRE(fn);
0217         REQUIRE(fn->name() == "function");
0218         REQUIRE(fn->signature() == "function(int & arg1, const int arg0 = 0)");
0219         REQUIRE(fn->returnType() == "int");
0220         REQUIRE(fn->templateParameters().empty());
0221         REQUIRE(fn->parent() == foo);
0222     });
0223 }
0224 
0225 TEST_CASE("Method declaration")
0226 {
0227     const static char *source = R"(
0228 class C {
0229     void method();
0230 };
0231 
0232 void C::method()
0233 {
0234 }
0235 )";
0236     ObjectStore session;
0237     REQUIRE(Test_Util::runOnCode(session, source, "testMethodDeclaration.cpp"));
0238 
0239     TypeObject *C = nullptr;
0240     MethodObject *method = nullptr;
0241 
0242     session.withROLock([&] {
0243         C = session.getType("C");
0244         method = session.getMethod("C::method", "method()", std::string{}, "void");
0245     });
0246     REQUIRE(method);
0247 
0248     method->withROLock([&] {
0249         REQUIRE(method->name() == "method");
0250         REQUIRE(method->signature() == "method()");
0251         REQUIRE(method->returnType() == "void");
0252         REQUIRE(method->templateParameters().empty());
0253         REQUIRE(!method->isVirtual());
0254         REQUIRE(!method->isPure());
0255         REQUIRE(!method->isStatic());
0256         REQUIRE(!method->isConst());
0257         REQUIRE(method->parent() == C);
0258         REQUIRE(method->argumentTypes().empty());
0259     });
0260 }
0261 
0262 TEST_CASE("Method access")
0263 {
0264     const static char *source = R"(
0265 class C {
0266   public:
0267     void pub() {}
0268 
0269   protected:
0270     void prot() {}
0271 
0272   private:
0273     void priv() {}
0274 };
0275 )";
0276     ObjectStore session;
0277     REQUIRE(Test_Util::runOnCode(session, source, "testMethodAccess.cpp"));
0278 
0279     MethodObject *pub = nullptr;
0280     MethodObject *prot = nullptr;
0281     MethodObject *priv = nullptr;
0282 
0283     session.withROLock([&] {
0284         pub = session.getMethod("C::pub", "pub()", std::string{}, "void");
0285         prot = session.getMethod("C::prot", "prot()", std::string{}, "void");
0286         priv = session.getMethod("C::priv", "priv()", std::string{}, "void");
0287     });
0288     REQUIRE(pub);
0289     REQUIRE(prot);
0290     REQUIRE(priv);
0291 
0292     pub->withROLock([&] {
0293         REQUIRE(pub->access() == lvtshr::AccessSpecifier::e_public);
0294     });
0295     prot->withROLock([&] {
0296         REQUIRE(prot->access() == lvtshr::AccessSpecifier::e_protected);
0297     });
0298     priv->withROLock([&] {
0299         REQUIRE(priv->access() == lvtshr::AccessSpecifier::e_private);
0300     });
0301 }
0302 
0303 TEST_CASE("Method specifiers")
0304 {
0305     const static char *source = R"(
0306 class C {
0307     virtual void virtMethod() {}
0308     virtual void pureMethod() = 0;
0309     static void staticMethod() {}
0310     void constMethod() const {}
0311 };
0312 )";
0313     ObjectStore session;
0314     REQUIRE(Test_Util::runOnCode(session, source, "testMethodSpecifiers.cpp"));
0315 
0316     MethodObject *virtMethod = nullptr;
0317     MethodObject *pureMethod = nullptr;
0318     MethodObject *staticMethod = nullptr;
0319     MethodObject *constMethod = nullptr;
0320 
0321     session.withROLock([&] {
0322         virtMethod = session.getMethod("C::virtMethod", "virtMethod()", std::string{}, "void");
0323         pureMethod = session.getMethod("C::pureMethod", "pureMethod()", std::string{}, "void");
0324         staticMethod = session.getMethod("C::staticMethod", "staticMethod()", std::string{}, "void");
0325         constMethod = session.getMethod("C::constMethod", "constMethod()", std::string{}, "void");
0326     });
0327 
0328     REQUIRE(virtMethod);
0329     REQUIRE(pureMethod);
0330     REQUIRE(staticMethod);
0331     REQUIRE(constMethod);
0332 
0333     virtMethod->withROLock([&] {
0334         REQUIRE(virtMethod->isVirtual());
0335         REQUIRE(!virtMethod->isPure());
0336         REQUIRE(!virtMethod->isStatic());
0337         REQUIRE(!virtMethod->isConst());
0338     });
0339 
0340     pureMethod->withRWLock([&] {
0341         REQUIRE(pureMethod->isVirtual());
0342         REQUIRE(pureMethod->isPure());
0343         REQUIRE(!pureMethod->isStatic());
0344         REQUIRE(!pureMethod->isConst());
0345     });
0346 
0347     staticMethod->withROLock([&] {
0348         REQUIRE(!staticMethod->isVirtual());
0349         REQUIRE(!staticMethod->isPure());
0350         REQUIRE(staticMethod->isStatic());
0351         REQUIRE(!staticMethod->isConst());
0352     });
0353 
0354     constMethod->withROLock([&] {
0355         REQUIRE(!constMethod->isVirtual());
0356         REQUIRE(!constMethod->isPure());
0357         REQUIRE(!constMethod->isStatic());
0358         REQUIRE(constMethod->isConst());
0359     });
0360 }
0361 
0362 TEST_CASE("Method arguments")
0363 {
0364     const static char *source = R"(
0365 class C {};
0366 class D {
0367     void method(int i, const C& c) {}
0368 };
0369 )";
0370     ObjectStore session;
0371     REQUIRE(Test_Util::runOnCode(session, source, "testMethodArguments.cpp"));
0372 
0373     MethodObject *method = nullptr;
0374     session.withROLock([&] {
0375         method = session.getMethod("D::method", "method(int i, const C & c)", std::string{}, "void");
0376     });
0377     REQUIRE(method);
0378 
0379     method->withROLock([&] {
0380         const auto argumentClasses = method->argumentTypes();
0381         REQUIRE(argumentClasses.size() == 1);
0382         auto *C = *argumentClasses.begin();
0383 
0384         C->withROLock([&] {
0385             REQUIRE(C->qualifiedName() == "C");
0386         });
0387     });
0388 }
0389 
0390 TEST_CASE("Method overload")
0391 {
0392     const static char *source = R"(
0393 class C {};
0394 
0395 class D {
0396     int foo ()
0397     {
0398         return 2;
0399     }
0400 
0401     int foo(C arg)
0402     {
0403         return 2;
0404     }
0405 };
0406 )";
0407     ObjectStore session;
0408     REQUIRE(Test_Util::runOnCode(session, source, "testMethodOverload.cpp"));
0409 
0410     TypeObject *C = nullptr;
0411     TypeObject *D = nullptr;
0412     MethodObject *foo0 = nullptr; // method without parameters
0413     MethodObject *foo1 = nullptr; // method with parameters
0414     session.withROLock([&] {
0415         C = session.getType("C");
0416         D = session.getType("D");
0417         foo0 = session.getMethod("D::foo", "foo()", std::string{}, "int");
0418         foo1 = session.getMethod("D::foo", "foo(C arg)", std::string{}, "int");
0419     });
0420 
0421     REQUIRE(C);
0422     REQUIRE(D);
0423     REQUIRE(foo0);
0424     REQUIRE(foo1);
0425 
0426     for (const auto& foo : {foo0, foo1}) {
0427         foo->withROLock([&] {
0428             REQUIRE(foo->qualifiedName() == "D::foo");
0429             REQUIRE(foo->returnType() == "int");
0430             REQUIRE(foo->templateParameters().empty());
0431             REQUIRE(foo->access() == lvtshr::AccessSpecifier::e_private);
0432             REQUIRE(!foo->isVirtual());
0433             REQUIRE(!foo->isPure());
0434             REQUIRE(!foo->isStatic());
0435             REQUIRE(!foo->isConst());
0436             REQUIRE(foo->parent() == D);
0437         });
0438     }
0439 
0440     foo0->withROLock([&] {
0441         REQUIRE(foo0->argumentTypes().empty());
0442     });
0443 
0444     foo1->withROLock([&] {
0445         const auto foo1Args = foo1->argumentTypes();
0446         REQUIRE(foo1Args.size() == 1);
0447         REQUIRE(*foo1Args.begin() == C);
0448     });
0449 }
0450 
0451 TEST_CASE("Method template")
0452 {
0453     const static char *source = R"(
0454 class C {
0455   public:
0456     template <typename T>
0457     T clone(const T& t)
0458     {
0459         return t;
0460     }
0461 };
0462 
0463 void instantiateSpecialization()
0464 {
0465     C c;
0466     int i = 2;
0467     int j = c.clone(i);
0468 }
0469 )";
0470     ObjectStore session;
0471     REQUIRE(Test_Util::runOnCode(session, source, "testMethodTemplate.cpp"));
0472 
0473     MethodObject *clone = nullptr;
0474     session.withROLock([&] {
0475         for (const auto& [_, fn] : session.methods()) {
0476             std::cout << "Key = --- \n" << _ << "\n ---\n";
0477         }
0478 
0479         clone = session.getMethod("C::clone", "clone(const T & t)", "template <typename T>", "type-parameter-0-0");
0480 
0481         // check we didn't separately add C::clone<int>
0482         REQUIRE(session.functions().size() == 1);
0483     });
0484     REQUIRE(clone);
0485 
0486     clone->withROLock([&] {
0487         REQUIRE(clone->templateParameters() == "template <typename T>");
0488     });
0489 }
0490 
0491 TEST_CASE("Method with default param")
0492 {
0493     const static char *source = R"(
0494 class C {
0495     void method(int i = 0);
0496 };
0497 
0498 void C::method(int i)
0499 {
0500 }
0501 )";
0502     ObjectStore session;
0503     REQUIRE(Test_Util::runOnCode(session, source, "testMethodDefaultParam.cpp"));
0504 
0505     TypeObject *C = nullptr;
0506     MethodObject *method = nullptr;
0507 
0508     session.withROLock([&] {
0509         C = session.getType("C");
0510         method = session.getMethod("C::method", "method(int i = 0)", std::string{}, "void");
0511     });
0512     REQUIRE(C);
0513     REQUIRE(method);
0514 
0515     method->withROLock([&] {
0516         REQUIRE(method->name() == "method");
0517         REQUIRE(method->signature() == "method(int i = 0)");
0518         REQUIRE(method->returnType() == "void");
0519         REQUIRE(method->templateParameters().empty());
0520         REQUIRE(!method->isVirtual());
0521         REQUIRE(!method->isPure());
0522         REQUIRE(!method->isStatic());
0523         REQUIRE(!method->isConst());
0524         REQUIRE(method->parent() == C);
0525         REQUIRE(method->argumentTypes().empty());
0526     });
0527 }
0528 
0529 TEST_CASE("Dependency via free function")
0530 {
0531     // We need both C and CFactory because variable declarations and static
0532     // function calls are tracked in different places in CodebaseDbVisitor
0533     const static char *source = R"(
0534 class C {
0535   public:
0536     void method(char c);
0537 };
0538 
0539 class CFactory {
0540   public:
0541     static C makeC();
0542 };
0543 
0544 static void freeFunction(char ch)
0545 {
0546     C c = CFactory::makeC();
0547     c.method(ch);
0548 }
0549 
0550 class D {
0551     void method()
0552     {
0553         freeFunction('D');
0554     }
0555 };
0556 
0557 class E {
0558     void method()
0559     {
0560         freeFunction('E');
0561     }
0562 };
0563 )";
0564     ObjectStore session;
0565     REQUIRE(Test_Util::runOnCode(session, source, "testDepViaFreeFunction.cpp"));
0566 
0567     REQUIRE(Test_Util::usesInTheImplementationExists("D", "CFactory", session));
0568     REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session));
0569     REQUIRE(Test_Util::usesInTheImplementationExists("E", "CFactory", session));
0570     REQUIRE(Test_Util::usesInTheImplementationExists("E", "C", session));
0571 }
0572 
0573 TEST_CASE("Dependency via function")
0574 {
0575     const static char *source = R"(
0576 class C {
0577   public:
0578     void method();
0579 };
0580 
0581 static void func1()
0582 {
0583     C c;
0584     c.method();
0585 }
0586 
0587 static void func2()
0588 {
0589     func1();
0590 }
0591 
0592 class D {
0593     void method()
0594     {
0595         func2();
0596     }
0597 };
0598 )";
0599     ObjectStore session;
0600     REQUIRE(Test_Util::runOnCode(session, source, "testDepViaFunctionViaFunction.cpp"));
0601 
0602     REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session));
0603 }
0604 
0605 TEST_CASE("Circular function dependency")
0606 {
0607     const static char *source = R"(
0608 class C {};
0609 class D {};
0610 
0611 static void funcC(bool b);
0612 static void funcD(bool b);
0613 
0614 static void funcC(bool b)
0615 {
0616     C c;
0617     if (b) {
0618         funcD(false);
0619     }
0620 }
0621 
0622 static void funcD(bool b)
0623 {
0624     D d;
0625     if (b) {
0626         funcC(false);
0627     }
0628 }
0629 
0630 class E {
0631     void method()
0632     {
0633         funcC(true);
0634     };
0635 };
0636 )";
0637     ObjectStore session;
0638     REQUIRE(Test_Util::runOnCode(session, source, "testDepViaCircularFunctionDep.cpp"));
0639 
0640     REQUIRE(Test_Util::usesInTheImplementationExists("E", "C", session));
0641     REQUIRE(Test_Util::usesInTheImplementationExists("E", "D", session));
0642 }
0643 
0644 TEST_CASE("Tricky function expansion")
0645 {
0646     // This is a bad test. It relies on the unordered_multimap in staticfnhandler
0647     // traversing x then y then z. On clang+gnu(?)+linux this seems to work by
0648     // the order functions appear in the file
0649     static const char *source = R"(
0650 class C {};
0651 
0652 static void x();
0653 static void y();
0654 static void z();
0655 
0656 static void x()
0657 {
0658     C c;
0659 }
0660 
0661 static void y()
0662 {
0663     x();
0664 }
0665 
0666 static void z()
0667 {
0668     y();
0669 }
0670 
0671 class D {
0672     void method()
0673     {
0674         z();
0675     }
0676 };
0677 )";
0678     ObjectStore session;
0679     REQUIRE(Test_Util::runOnCode(session, source, "testTrickyFUnctionExpansion.cpp"));
0680 
0681     REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session));
0682 }
0683 
0684 TEST_CASE("Function dependency overload")
0685 {
0686     // check that the code for detecting uses-in-impl relationships via static
0687     // free functions isn't confused by overloaded functions
0688     static const char *source = R"(
0689 class C {};
0690 class D {};
0691 
0692 static void freeFunction(int arg)
0693 {
0694     C c;
0695 }
0696 
0697 static void freeFunction(bool arg)
0698 {
0699     D d;
0700 }
0701 
0702 class UsesC {
0703     void method()
0704     {
0705         freeFunction(42);
0706     }
0707 };
0708 
0709 class UsesD {
0710     void method()
0711     {
0712         freeFunction(true);
0713     }
0714 };
0715 )";
0716     ObjectStore session;
0717     REQUIRE(Test_Util::runOnCode(session, source, "testFunctionDepOverload.cpp"));
0718 
0719     REQUIRE(Test_Util::usesInTheImplementationExists("UsesC", "C", session));
0720     REQUIRE(Test_Util::usesInTheImplementationExists("UsesD", "D", session));
0721     REQUIRE(!Test_Util::usesInTheImplementationExists("UsesC", "D", session));
0722     REQUIRE(!Test_Util::usesInTheImplementationExists("UsesD", "C", session));
0723 }
0724 
0725 // TODO: Review this. Should an indirect call to a static class member through a free function infer a direct
0726 // dependency? I think no. But the original writer of this test believes yes. Perhaps because at the time, we didn't
0727 // have the free functions as entities, so it kind of make sense, but now that we do have them, I think the indirect
0728 // dependency should be enough. The same applies for the test above, which is _not_ failing, but I believe it should
0729 // fail. All that must be revisited.
0730 //
0731 // clang-format off
0732 //TEST_CASE("Function dependency with template")
0733 //{
0734 //    // check that the code for detecting uses-in-impl relationships via static
0735 //    // free functions isn't confused by template specializations
0736 //    static const char *source = R"(
0737 //class C {};
0738 //class D { public: static void method(); };
0739 //
0740 //template <class TYPE>
0741 //static void freeFunction();
0742 //
0743 //template <>
0744 //void freeFunction<int>()
0745 //{
0746 //    // test CodebaseDbVisitor::visitLocalVarDeclOrParam path
0747 //    C c;
0748 //}
0749 //
0750 //template <>
0751 //void freeFunction<bool>()
0752 //{
0753 //    // test CodebaseDbVisitor::searchClangStmtAST path
0754 //    D::method();
0755 //}
0756 //
0757 //class UsesC {
0758 //    void method()
0759 //    {
0760 //        freeFunction<int>();
0761 //    }
0762 //};
0763 //
0764 //class UsesD {
0765 //    void method()
0766 //    {
0767 //        freeFunction<bool>();
0768 //    }
0769 //};
0770 //)";
0771 //    ObjectStore session;
0772 //    REQUIRE(Test_Util::runOnCode(session, source, "testFunctionDepTemplate.cpp"));
0773 //
0774 //    REQUIRE(Test_Util::usesInTheImplementationExists("UsesC", "C", session));
0775 //    REQUIRE(Test_Util::usesInTheImplementationExists("UsesD", "D", session));
0776 //    REQUIRE(!Test_Util::usesInTheImplementationExists("UsesC", "D", session));
0777 //    REQUIRE(!Test_Util::usesInTheImplementationExists("UsesD", "C", session));
0778 //}
0779 // clang-format on