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 }