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

0001 // ct_lvtclp_testfield.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::VisitFieldDecl
0021 
0022 #include <ct_lvtmdb_fieldobject.h>
0023 #include <ct_lvtmdb_objectstore.h>
0024 #include <ct_lvtmdb_typeobject.h>
0025 
0026 #include <ct_lvtclp_testutil.h>
0027 #include <ct_lvtshr_graphenums.h>
0028 
0029 #include <algorithm>
0030 #include <cstdlib>
0031 #include <iostream>
0032 
0033 #include <catch2-local-includes.h>
0034 #include <clang/Basic/Version.h>
0035 
0036 using namespace Codethink::lvtclp;
0037 using namespace Codethink::lvtmdb;
0038 using namespace Codethink;
0039 
0040 const PyDefaultGilReleasedContext defaultGilContextForTesting;
0041 
0042 TEST_CASE("Field declaration")
0043 {
0044     const static char *source = R"(
0045 class C {
0046     int i;
0047 };
0048 )";
0049     ObjectStore session;
0050     REQUIRE(Test_Util::runOnCode(session, source, "testFieldDecl.cpp"));
0051 
0052     TypeObject *C = nullptr;
0053     FieldObject *i = nullptr;
0054     session.withROLock([&] {
0055         C = session.getType("C");
0056         i = session.getField("C::i");
0057     });
0058     REQUIRE(C);
0059     REQUIRE(i);
0060 
0061     i->withROLock([&] {
0062         REQUIRE(i->name() == "i");
0063         REQUIRE(i->signature() == "int");
0064         REQUIRE(i->access() == lvtshr::AccessSpecifier::e_private);
0065         REQUIRE(!i->isStatic());
0066         REQUIRE(i->parent() == C);
0067 
0068         // int is not a class
0069         REQUIRE(i->variableTypes().empty());
0070     });
0071 }
0072 
0073 TEST_CASE("Field signatures")
0074 {
0075     const static char *source = R"(
0076 class C {
0077     int val;
0078     int *ptr;
0079     int& ref = val;
0080 
0081     const int constVal = 0;
0082     volatile int volatileVal;
0083 };
0084 )";
0085     ObjectStore session;
0086     REQUIRE(Test_Util::runOnCode(session, source, "testFieldSignatures.cpp"));
0087 
0088     FieldObject *val = nullptr;
0089     FieldObject *ptr = nullptr;
0090     FieldObject *ref = nullptr;
0091     FieldObject *constVal = nullptr;
0092     FieldObject *volatileVal = nullptr;
0093     session.withROLock([&] {
0094         val = session.getField("C::val");
0095         ptr = session.getField("C::ptr");
0096         ref = session.getField("C::ref");
0097         constVal = session.getField("C::constVal");
0098         volatileVal = session.getField("C::volatileVal");
0099     });
0100 
0101     REQUIRE(val);
0102     REQUIRE(ptr);
0103     REQUIRE(ref);
0104     REQUIRE(constVal);
0105     REQUIRE(volatileVal);
0106 
0107     val->withROLock([&] {
0108         REQUIRE(val->signature() == "int");
0109     });
0110 
0111     ptr->withROLock([&] {
0112         REQUIRE(ptr->signature() == "int *");
0113     });
0114 
0115     ref->withROLock([&] {
0116         REQUIRE(ref->signature() == "int &");
0117     });
0118 
0119     constVal->withROLock([&] {
0120         REQUIRE(constVal->signature() == "const int");
0121     });
0122 
0123     volatileVal->withROLock([&] {
0124         REQUIRE(volatileVal->signature() == "volatile int");
0125     });
0126 }
0127 
0128 TEST_CASE("Field access")
0129 {
0130     const static char *source = R"(
0131 class C {
0132   public:
0133     int pub;
0134 
0135   protected:
0136     int prot;
0137 
0138   private:
0139     int priv;
0140 };
0141 )";
0142     ObjectStore session;
0143     REQUIRE(Test_Util::runOnCode(session, source, "testFieldAccess.cpp"));
0144 
0145     using AS = lvtshr::AccessSpecifier;
0146 
0147     FieldObject *pub = nullptr;
0148     FieldObject *prot = nullptr;
0149     FieldObject *priv = nullptr;
0150 
0151     session.withROLock([&] {
0152         pub = session.getField("C::pub");
0153         prot = session.getField("C::prot");
0154         priv = session.getField("C::priv");
0155     });
0156     REQUIRE(pub);
0157     REQUIRE(prot);
0158     REQUIRE(priv);
0159 
0160     pub->withROLock([&] {
0161         REQUIRE(pub->access() == AS::e_public);
0162     });
0163 
0164     prot->withROLock([&] {
0165         REQUIRE(prot->access() == AS::e_protected);
0166     });
0167 
0168     priv->withROLock([&] {
0169         REQUIRE(priv->access() == AS::e_private);
0170     });
0171 }
0172 
0173 TEST_CASE("Field relations")
0174 {
0175     const static char *source = R"(
0176 class Pub {};
0177 class Prot {};
0178 class Priv {};
0179 
0180 class C {
0181   public:
0182     Pub pub;
0183 
0184   protected:
0185     Prot prot;
0186 
0187   private:
0188     Priv priv;
0189 };
0190 )";
0191     ObjectStore session;
0192     REQUIRE(Test_Util::runOnCode(session, source, "testFieldRelations.cpp"));
0193 
0194     REQUIRE(Test_Util::usesInTheInterfaceExists("C", "Pub", session));
0195     REQUIRE(!Test_Util::usesInTheImplementationExists("C", "Pub", session));
0196     REQUIRE(Test_Util::usesInTheInterfaceExists("C", "Prot", session));
0197     REQUIRE(!Test_Util::usesInTheImplementationExists("C", "Prot", session));
0198     REQUIRE(!Test_Util::usesInTheInterfaceExists("C", "Priv", session));
0199     REQUIRE(Test_Util::usesInTheImplementationExists("C", "Priv", session));
0200 }
0201 
0202 TEST_CASE("Static fields")
0203 {
0204     const static char *source = R"(
0205 class C {
0206     static int i;
0207 };
0208 )";
0209     ObjectStore session;
0210     REQUIRE(Test_Util::runOnCode(session, source, "testStaticField.cpp"));
0211 
0212     FieldObject *i = nullptr;
0213     session.withROLock([&] {
0214         i = session.getField("C::i");
0215     });
0216     REQUIRE(i);
0217 
0218     i->withROLock([&] {
0219         REQUIRE(i->isStatic());
0220     });
0221 }
0222 
0223 TEST_CASE("Field types")
0224 {
0225     const static char *source = R"(
0226 class C {};
0227 class D {
0228     C c;
0229 };
0230 )";
0231     ObjectStore session;
0232     REQUIRE(Test_Util::runOnCode(session, source, "testFieldTypes.cpp"));
0233 
0234     TypeObject *cType = nullptr;
0235     FieldObject *cField = nullptr;
0236     session.withROLock([&] {
0237         cType = session.getType("C");
0238         cField = session.getField("D::c");
0239     });
0240     REQUIRE(cType);
0241     REQUIRE(cField);
0242 
0243     cField->withROLock([&] {
0244         const auto variableTypes = cField->variableTypes();
0245         REQUIRE(variableTypes.size() == 1);
0246         REQUIRE(*variableTypes.begin() == cType);
0247     });
0248 }
0249 
0250 TEST_CASE("Field template")
0251 {
0252     const static char *source = R"(
0253 class T {};
0254 
0255 template <typename T>
0256 class C {};
0257 
0258 template <typename T>
0259 class D {};
0260 
0261 class E {};
0262 
0263 class F {
0264     C<D<E>> cde;
0265 };
0266 )";
0267     ObjectStore session;
0268     REQUIRE(Test_Util::runOnCode(session, source, "testFieldTemplate.cpp"));
0269 
0270     TypeObject *C = nullptr;
0271     TypeObject *D = nullptr;
0272     TypeObject *E = nullptr;
0273     FieldObject *cde = nullptr;
0274     session.withROLock([&] {
0275         C = session.getType("C");
0276         D = session.getType("D");
0277         E = session.getType("E");
0278         cde = session.getField("F::cde");
0279     });
0280     REQUIRE(C);
0281     REQUIRE(D);
0282     REQUIRE(E);
0283     REQUIRE(cde);
0284 
0285     cde->withROLock([&] {
0286         REQUIRE(cde->signature() == "C<D<E> >");
0287 
0288         const auto variableTypes = cde->variableTypes();
0289         REQUIRE(variableTypes.size() == 3);
0290         auto it = std::find(variableTypes.begin(), variableTypes.end(), C);
0291         REQUIRE(it != variableTypes.end());
0292         it = std::find(variableTypes.begin(), variableTypes.end(), D);
0293         REQUIRE(it != variableTypes.end());
0294         it = std::find(variableTypes.begin(), variableTypes.end(), E);
0295         REQUIRE(it != variableTypes.end());
0296     });
0297 
0298     REQUIRE(Test_Util::usesInTheImplementationExists("F", "C", session));
0299     REQUIRE(Test_Util::usesInTheImplementationExists("F", "D", session));
0300     REQUIRE(Test_Util::usesInTheImplementationExists("F", "E", session));
0301     REQUIRE(!Test_Util::usesInTheImplementationExists("C", "T", session));
0302     REQUIRE(!Test_Util::usesInTheImplementationExists("D", "T", session));
0303     REQUIRE(!Test_Util::usesInTheImplementationExists("E", "T", session));
0304     REQUIRE(!Test_Util::usesInTheImplementationExists("F", "T", session));
0305 }
0306 
0307 TEST_CASE("Field class template")
0308 {
0309     const static char *source = R"(
0310 class T {};
0311 
0312 template <typename T>
0313 class C {
0314     T t;
0315 };
0316 
0317 class D {};
0318 
0319 class E {
0320     C<D> cd;
0321 };
0322 )";
0323     ObjectStore session;
0324     REQUIRE(Test_Util::runOnCode(session, source, "testFieldClassTemplate.cpp"));
0325 
0326     TypeObject *C = nullptr;
0327     TypeObject *D = nullptr;
0328     FieldObject *t = nullptr;
0329     FieldObject *cd = nullptr;
0330 
0331     session.withROLock([&] {
0332         C = session.getType("C");
0333         D = session.getType("D");
0334         t = session.getField("C::t");
0335         cd = session.getField("E::cd");
0336     });
0337 
0338     REQUIRE(C);
0339     REQUIRE(D);
0340     REQUIRE(t);
0341     REQUIRE(cd);
0342 
0343     t->withROLock([&] {
0344         REQUIRE(t->signature() == "T");
0345         REQUIRE(t->variableTypes().empty());
0346     });
0347 
0348     cd->withROLock([&] {
0349         REQUIRE(cd->signature() == "C<D>");
0350         const auto cdVariableTypes = cd->variableTypes();
0351         REQUIRE(cdVariableTypes.size() == 2);
0352         auto it = std::find(cdVariableTypes.begin(), cdVariableTypes.end(), C);
0353         REQUIRE(it != cdVariableTypes.end());
0354         it = std::find(cdVariableTypes.begin(), cdVariableTypes.end(), D);
0355         REQUIRE(it != cdVariableTypes.end());
0356     });
0357 
0358     REQUIRE(Test_Util::usesInTheImplementationExists("E", "C", session));
0359     REQUIRE(Test_Util::usesInTheImplementationExists("E", "D", session));
0360     REQUIRE(!Test_Util::usesInTheImplementationExists("C", "T", session));
0361 }
0362 
0363 TEST_CASE("Anon field")
0364 {
0365     const static char *source = R"(
0366 struct Foo {
0367     unsigned one;
0368     int :32; // padding
0369     unsigned two;
0370 };
0371 )";
0372     ObjectStore session;
0373     REQUIRE(Test_Util::runOnCode(session, source, "testAnonField.cpp"));
0374 
0375     TypeObject *foo = nullptr;
0376     session.withROLock([&] {
0377         foo = session.getType("Foo");
0378     });
0379 
0380     REQUIRE(foo);
0381     foo->withROLock([&] {
0382         REQUIRE(foo->fields().size() == 2);
0383     });
0384 }