File indexing completed on 2024-05-19 05:42:05
0001 // ct_lvtclp_testvar.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 CodebaseDbVisitor::VisitVarDecl 0021 // (except for static class member variables, which are in testfield) 0022 0023 #include <ct_lvtmdb_namespaceobject.h> 0024 #include <ct_lvtmdb_objectstore.h> 0025 #include <ct_lvtmdb_typeobject.h> 0026 #include <ct_lvtmdb_variableobject.h> 0027 0028 #include <ct_lvtclp_testutil.h> 0029 0030 #include <catch2-local-includes.h> 0031 #include <clang/Basic/Version.h> 0032 0033 using namespace Codethink::lvtclp; 0034 using namespace Codethink::lvtmdb; 0035 0036 const PyDefaultGilReleasedContext defaultGilContextForTesting; 0037 0038 TEST_CASE("Local variable declaration") 0039 { 0040 const static char *source = R"( 0041 class C {}; 0042 0043 class D { 0044 void method() 0045 { 0046 C c; 0047 } 0048 }; 0049 )"; 0050 ObjectStore session; 0051 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarDecl.cpp")); 0052 0053 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0054 } 0055 0056 TEST_CASE("Local variable anon parent") 0057 { 0058 const static char *source = R"( 0059 class C {}; 0060 0061 class { 0062 void method() 0063 { 0064 C c; 0065 } 0066 } d; 0067 )"; 0068 ObjectStore session; 0069 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarAnonParent.cpp")); 0070 0071 // check there are no usesInTheImpl relationships in the database 0072 session.withROLock([&] { 0073 for (const auto& [_, klass] : session.types()) { 0074 auto *k = klass.get(); 0075 klass->withROLock([k] { 0076 REQUIRE(k->usesInTheImplementation().empty()); 0077 }); 0078 } 0079 }); 0080 } 0081 0082 TEST_CASE("Local variable anon type") 0083 { 0084 const static char *source = R"( 0085 class C { 0086 void method() 0087 { 0088 class {} c; 0089 } 0090 }; 0091 )"; 0092 ObjectStore session; 0093 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarAnonType.cpp")); 0094 0095 // check there are no usesInTheImpl relationships in the database 0096 session.withROLock([&] { 0097 for (const auto& [_, klass] : session.types()) { 0098 auto *k = klass.get(); 0099 klass->withROLock([k] { 0100 REQUIRE(k->usesInTheImplementation().empty()); 0101 }); 0102 } 0103 }); 0104 } 0105 0106 TEST_CASE("Local variable template method") 0107 { 0108 const static char *source = R"( 0109 class T {}; 0110 0111 class C {}; 0112 0113 class D {}; 0114 0115 class E { 0116 public: 0117 template <typename T> 0118 void method() 0119 { 0120 C c; 0121 } 0122 }; 0123 0124 void function() 0125 { 0126 E e; 0127 e.method<D>(); 0128 } 0129 )"; 0130 ObjectStore session; 0131 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarTemplateMethod.cpp")); 0132 0133 REQUIRE(Test_Util::usesInTheImplementationExists("E", "C", session)); 0134 REQUIRE(!Test_Util::usesInTheImplementationExists("E", "T", session)); 0135 REQUIRE(!Test_Util::usesInTheImplementationExists("E", "D", session)); 0136 } 0137 0138 TEST_CASE("Local variable template method 2") 0139 { 0140 const static char *source = R"( 0141 class T {}; 0142 0143 class D {}; 0144 0145 class E { 0146 public: 0147 template <typename T> 0148 void method() 0149 { 0150 T t; 0151 } 0152 }; 0153 0154 void function() 0155 { 0156 E e; 0157 e.method<D>(); 0158 } 0159 )"; 0160 ObjectStore session; 0161 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarTemplateMethod2.cpp")); 0162 0163 REQUIRE(!Test_Util::usesInTheImplementationExists("E", "T", session)); 0164 REQUIRE(!Test_Util::usesInTheImplementationExists("E", "D", session)); 0165 } 0166 0167 TEST_CASE("Local variable template class") 0168 { 0169 const static char *source = R"( 0170 class T {}; 0171 class C {}; 0172 class D {}; 0173 0174 template <typename T> 0175 class E { 0176 public: 0177 void method() 0178 { 0179 C c; 0180 } 0181 }; 0182 0183 void function() 0184 { 0185 E<D> ed; 0186 ed.method(); 0187 } 0188 )"; 0189 ObjectStore session; 0190 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarTemplateClass.cpp")); 0191 0192 REQUIRE(Test_Util::usesInTheImplementationExists("E", "C", session)); 0193 REQUIRE(!Test_Util::usesInTheImplementationExists("E", "T", session)); 0194 REQUIRE(!Test_Util::usesInTheImplementationExists("E", "D", session)); 0195 } 0196 0197 TEST_CASE("Local variable template class 2") 0198 { 0199 const static char *source = R"( 0200 class T {}; 0201 class D {}; 0202 0203 template <typename T> 0204 class E { 0205 public: 0206 void method() 0207 { 0208 T t; 0209 } 0210 }; 0211 0212 void function() 0213 { 0214 E<D> ed; 0215 ed.method(); 0216 } 0217 )"; 0218 ObjectStore session; 0219 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarTemplateClass2.cpp")); 0220 0221 REQUIRE(!Test_Util::usesInTheImplementationExists("E", "T", session)); 0222 REQUIRE(!Test_Util::usesInTheImplementationExists("E", "D", session)); 0223 } 0224 0225 TEST_CASE("Local variable lambda in method") 0226 { 0227 const static char *source = R"( 0228 class C {}; 0229 0230 class D { 0231 void method() 0232 { 0233 auto lambda = []() { 0234 C c; 0235 }; 0236 } 0237 }; 0238 )"; 0239 ObjectStore session; 0240 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarLambdaInMethod.cpp")); 0241 0242 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0243 } 0244 0245 TEST_CASE("Local variable lambda in lambda in method") 0246 { 0247 const static char *source = R"( 0248 class C {}; 0249 0250 class D { 0251 void method() 0252 { 0253 auto lambda = []() { 0254 auto lambda2 = []() { 0255 C c; 0256 }; 0257 }; 0258 } 0259 }; 0260 )"; 0261 ObjectStore session; 0262 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarLambdaInLambdaInMethod.cpp")); 0263 0264 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0265 } 0266 0267 TEST_CASE("Local variable lambda in field") 0268 { 0269 const static char *source = R"( 0270 class C {}; 0271 0272 class D { 0273 // auto not allowed in non-static class member 0274 // auto variables must be initialized at declaration 0275 // only constexpr static members can be initialized at declaration 0276 static constexpr auto lambda = []() { 0277 C c; 0278 }; 0279 }; 0280 )"; 0281 ObjectStore session; 0282 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarLambdaInField.cpp")); 0283 0284 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0285 } 0286 0287 TEST_CASE("Local variable in block") 0288 { 0289 const static char *source = R"( 0290 class C {}; 0291 0292 class D { 0293 void method() 0294 { 0295 { 0296 C c; 0297 } 0298 } 0299 }; 0300 )"; 0301 ObjectStore session; 0302 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarInBlock.cpp")); 0303 0304 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0305 } 0306 0307 TEST_CASE("Method arg relation") 0308 { 0309 const static char *source = R"( 0310 class Pub {}; 0311 class Prot {}; 0312 class Priv {}; 0313 0314 class C { 0315 public: 0316 void pubMethod(Pub p) {} 0317 0318 protected: 0319 void protMethod(Prot p) {} 0320 0321 private: 0322 void privMethod(Priv p) {} 0323 }; 0324 )"; 0325 ObjectStore session; 0326 REQUIRE(Test_Util::runOnCode(session, source, "testMethodArgRelation.cpp")); 0327 0328 REQUIRE(Test_Util::usesInTheInterfaceExists("C", "Pub", session)); 0329 REQUIRE(!Test_Util::usesInTheImplementationExists("C", "Pub", session)); 0330 REQUIRE(Test_Util::usesInTheInterfaceExists("C", "Prot", session)); 0331 REQUIRE(!Test_Util::usesInTheImplementationExists("C", "Prot", session)); 0332 REQUIRE(!Test_Util::usesInTheInterfaceExists("C", "Priv", session)); 0333 REQUIRE(Test_Util::usesInTheImplementationExists("C", "Priv", session)); 0334 } 0335 0336 TEST_CASE("Method template arg") 0337 { 0338 const static char *source = R"( 0339 template <typename T> 0340 class C {}; 0341 0342 template <typename T> 0343 class D {}; 0344 0345 class E {}; 0346 0347 class F {}; 0348 0349 // see if we can trip up our parsing 0350 class T {}; 0351 0352 class G { 0353 public: 0354 void method(C<D<E>> cde) {} 0355 0356 template <typename T> 0357 void templateMethod(C<T> ct) {} 0358 0359 private: 0360 void privMethod(C<F> cf) {} 0361 }; 0362 )"; 0363 ObjectStore session; 0364 REQUIRE(Test_Util::runOnCode(session, source, "testMethodTemplateArg.cpp")); 0365 0366 REQUIRE(Test_Util::usesInTheInterfaceExists("G", "C", session)); 0367 REQUIRE(Test_Util::usesInTheInterfaceExists("G", "D", session)); 0368 REQUIRE(Test_Util::usesInTheInterfaceExists("G", "E", session)); 0369 REQUIRE(!Test_Util::usesInTheInterfaceExists("G", "T", session)); 0370 REQUIRE(!Test_Util::usesInTheInterfaceExists("G", "F", session)); 0371 REQUIRE(Test_Util::usesInTheImplementationExists("G", "F", session)); 0372 } 0373 0374 TEST_CASE("Lambda args in method") 0375 { 0376 const static char *source = R"( 0377 class C {}; 0378 0379 class D { 0380 public: 0381 void method() 0382 { 0383 auto foo = [](C& c){}; 0384 } 0385 }; 0386 )"; 0387 ObjectStore session; 0388 REQUIRE(Test_Util::runOnCode(session, source, "testLambdaArgsInMethod.cpp")); 0389 0390 // the method is public but the lambda is an implementation detail inside 0391 // the method so C should be usesInTheImplementation, despite C being used 0392 // as a method parameter 0393 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0394 REQUIRE(!Test_Util::usesInTheInterfaceExists("D", "C", session)); 0395 } 0396 0397 TEST_CASE("Lambda args in field") 0398 { 0399 const static char *source = R"( 0400 class Pub {}; 0401 class Prot {}; 0402 class Priv {}; 0403 0404 class C { 0405 public: 0406 static constexpr auto pub = [](Pub p) {}; 0407 0408 protected: 0409 static constexpr auto prot = [](Prot& p) {}; 0410 0411 private: 0412 static constexpr auto priv = [](Priv *p) {}; 0413 }; 0414 )"; 0415 ObjectStore session; 0416 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarLambdaInField.cpp")); 0417 0418 REQUIRE(Test_Util::usesInTheInterfaceExists("C", "Pub", session)); 0419 REQUIRE(!Test_Util::usesInTheImplementationExists("C", "Pub", session)); 0420 REQUIRE(Test_Util::usesInTheInterfaceExists("C", "Prot", session)); 0421 REQUIRE(!Test_Util::usesInTheImplementationExists("C", "Prot", session)); 0422 REQUIRE(!Test_Util::usesInTheInterfaceExists("C", "Priv", session)); 0423 REQUIRE(Test_Util::usesInTheImplementationExists("C", "Priv", session)); 0424 } 0425 0426 TEST_CASE("Lambda args in lambda in field") 0427 { 0428 const static char *source = R"( 0429 class C {}; 0430 0431 class D { 0432 public: 0433 static constexpr auto pub = []() { 0434 auto innerLambda = [](C c) {}; 0435 }; 0436 }; 0437 )"; 0438 ObjectStore session; 0439 REQUIRE(Test_Util::runOnCode(session, source, "testLocalVarLambdaInLambdaInField.cpp")); 0440 0441 REQUIRE(!Test_Util::usesInTheInterfaceExists("D", "C", session)); 0442 REQUIRE(Test_Util::usesInTheImplementationExists("D", "C", session)); 0443 } 0444 0445 TEST_CASE("Generic lambda args") 0446 { 0447 const static char *source = R"( 0448 class C {}; 0449 0450 class D { 0451 public: 0452 static constexpr auto lambda = [](auto foo) {}; 0453 }; 0454 0455 class E { 0456 void method() 0457 { 0458 D::lambda(C()); 0459 } 0460 }; 0461 )"; 0462 ObjectStore session; 0463 REQUIRE(Test_Util::runOnCode(session, source, "testGenericLambdaArgs.cpp")); 0464 0465 REQUIRE(Test_Util::usesInTheImplementationExists("E", "D", session)); 0466 REQUIRE(Test_Util::usesInTheImplementationExists("E", "C", session)); 0467 REQUIRE(!Test_Util::usesInTheImplementationExists("D", "C", session)); 0468 REQUIRE(!Test_Util::usesInTheInterfaceExists("D", "C", session)); 0469 } 0470 0471 TEST_CASE("Namespace var decl") 0472 { 0473 static const char *source = R"( 0474 class C; 0475 0476 namespace foo { 0477 0478 C *c; 0479 0480 } 0481 )"; 0482 ObjectStore session; 0483 REQUIRE(Test_Util::runOnCode(session, source, "testNamespaceVarDecl.cpp")); 0484 0485 NamespaceObject *foo = nullptr; 0486 VariableObject *c = nullptr; 0487 0488 session.withROLock([&] { 0489 foo = session.getNamespace("foo"); 0490 c = session.getVariable("foo::c"); 0491 }); 0492 REQUIRE(foo); 0493 REQUIRE(c); 0494 0495 c->withROLock([&] { 0496 REQUIRE(c->name() == "c"); 0497 REQUIRE(c->parent() == foo); 0498 REQUIRE(!c->isGlobal()); 0499 REQUIRE(c->signature() == "C *"); 0500 }); 0501 } 0502 0503 TEST_CASE("Global var decl") 0504 { 0505 static const char *source = R"( 0506 class C; 0507 0508 C *c; 0509 )"; 0510 ObjectStore session; 0511 REQUIRE(Test_Util::runOnCode(session, source, "testGlobalVarDecl.cpp")); 0512 0513 VariableObject *c = nullptr; 0514 0515 session.withROLock([&] { 0516 c = session.getVariable("c"); 0517 }); 0518 REQUIRE(c); 0519 0520 c->withROLock([&] { 0521 REQUIRE(c->name() == "c"); 0522 REQUIRE(!c->parent()); 0523 REQUIRE(c->isGlobal()); 0524 REQUIRE(c->signature() == "C *"); 0525 }); 0526 } 0527 0528 TEST_CASE("Constexpr global var") 0529 { 0530 static const char *source = R"( 0531 namespace foo { 0532 0533 constexpr double pi = 3.141592654; 0534 0535 } 0536 )"; 0537 ObjectStore session; 0538 REQUIRE(Test_Util::runOnCode(session, source, "testConstexprGlobalVar.cpp")); 0539 0540 NamespaceObject *foo = nullptr; 0541 VariableObject *pi = nullptr; 0542 0543 session.withROLock([&] { 0544 foo = session.getNamespace("foo"); 0545 pi = session.getVariable("foo::pi"); 0546 }); 0547 REQUIRE(foo); 0548 REQUIRE(pi); 0549 0550 pi->withROLock([&] { 0551 REQUIRE(pi->name() == "pi"); 0552 REQUIRE(pi->parent() == foo); 0553 REQUIRE(!pi->isGlobal()); 0554 REQUIRE(pi->signature() == "const double"); 0555 }); 0556 }