File indexing completed on 2024-05-19 05:42:01
0001 // ct_lvtclp_dumpdatabase.m.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 // Prints a database to stdout in a sorted, human readable format. 0021 // This is useful for calculating diffs of databases (sqlite's .DUMP command 0022 // isn't useful because it shows the database IDs). 0023 // 0024 // Obviously, this outputs a huge amount of text. 0025 #include "ct_lvtmdb_methodobject.h" 0026 #include <ct_lvtmdb_componentobject.h> 0027 #include <ct_lvtmdb_fieldobject.h> 0028 #include <ct_lvtmdb_fileobject.h> 0029 #include <ct_lvtmdb_namespaceobject.h> 0030 #include <ct_lvtmdb_objectstore.h> 0031 #include <ct_lvtmdb_packageobject.h> 0032 #include <ct_lvtmdb_soci_reader.h> 0033 #include <ct_lvtmdb_typeobject.h> 0034 0035 #include <ct_lvtprj_projectfile.h> 0036 0037 #include <ct_lvtshr_stringhelpers.h> 0038 0039 #include <algorithm> 0040 #include <cstdlib> 0041 #include <cstring> 0042 #include <filesystem> 0043 #include <iostream> 0044 #include <iterator> 0045 #include <memory> 0046 #include <vector> 0047 0048 #include <QDebug> 0049 0050 using namespace Codethink; 0051 using namespace Codethink::lvtmdb; 0052 0053 static void printHelp(const char *execName) 0054 { 0055 qDebug() << "Dump database to stdout"; 0056 qDebug() << "USAGE: " << execName << " <PATH>"; 0057 qDebug() << "ARGUMENTS:"; 0058 qDebug() << "PATH\t\tPath to the project file"; 0059 } 0060 0061 template<typename T> 0062 static void sort(std::vector<T *>& vec) 0063 { 0064 std::sort(vec.begin(), vec.end(), [](const auto& a, const auto& b) { 0065 auto a_lock = a->readOnlyLock(); 0066 (void) a_lock; 0067 auto b_lock = b->readOnlyLock(); 0068 (void) b_lock; 0069 0070 return a->qualifiedName() < b->qualifiedName(); 0071 }); 0072 } 0073 0074 static void printFile(FileObject *file) 0075 { 0076 auto lock = file->readOnlyLock(); 0077 (void) lock; 0078 qDebug() << " " << file->qualifiedName(); 0079 0080 const auto& parent = file->package(); 0081 if (parent) { 0082 auto p_lock = parent->readOnlyLock(); 0083 (void) p_lock; 0084 qDebug() << " PARENT: " << parent->qualifiedName(); 0085 } 0086 0087 std::vector<NamespaceObject *> nmspcs = file->namespaces(); 0088 sort(nmspcs); 0089 if (!nmspcs.empty()) { 0090 qDebug() << " NAMESPACES:"; 0091 } 0092 for (const auto& nmspc : nmspcs) { 0093 auto n_lock = nmspc->readOnlyLock(); 0094 (void) n_lock; 0095 qDebug() << " " << nmspc->qualifiedName(); 0096 } 0097 0098 std::vector<TypeObject *> classes = file->types(); 0099 sort(classes); 0100 if (!classes.empty()) { 0101 qDebug() << " CLASSES:"; 0102 } 0103 for (const auto& klass : classes) { 0104 auto n_lock = klass->readOnlyLock(); 0105 (void) n_lock; 0106 qDebug() << " " << klass->qualifiedName(); 0107 } 0108 0109 std::vector<FileObject *> includes = file->forwardIncludes(); 0110 sort(includes); 0111 if (!includes.empty()) { 0112 qDebug() << " INCLUDES:"; 0113 } 0114 0115 for (const auto& include : includes) { 0116 auto n_lock = include->readOnlyLock(); 0117 (void) n_lock; 0118 qDebug() << " " << include->qualifiedName(); 0119 } 0120 0121 qDebug(); 0122 } 0123 0124 static void printFiles(ObjectStore& session) 0125 { 0126 qDebug() << "SOURCE FILES:"; 0127 for (const auto& [_, file] : session.files()) { 0128 (void) _; 0129 printFile(file.get()); 0130 } 0131 } 0132 0133 static void printPackage(PackageObject *package) 0134 { 0135 auto lock = package->readOnlyLock(); 0136 (void) lock; 0137 qDebug() << " " << package->qualifiedName(); 0138 0139 PackageObject *parent = package->parent(); 0140 if (parent) { 0141 qDebug() << " PARENT: " << parent->qualifiedName(); 0142 } 0143 0144 std::vector<TypeObject *> classes = package->types(); 0145 sort(classes); 0146 if (!classes.empty()) { 0147 qDebug() << " CLASSES:"; 0148 } 0149 0150 for (const auto& klass : classes) { 0151 auto k_lock = klass->readOnlyLock(); 0152 (void) k_lock; 0153 qDebug() << " " << klass->qualifiedName(); 0154 } 0155 0156 std::vector<PackageObject *> dependencies = package->forwardDependencies(); 0157 0158 sort(dependencies); 0159 if (!dependencies.empty()) { 0160 qDebug() << " DEPENDENCIES:"; 0161 } 0162 for (const auto& pkgDep : dependencies) { 0163 auto p_lock = pkgDep->readOnlyLock(); 0164 (void) p_lock; 0165 qDebug() << " " << pkgDep->qualifiedName(); 0166 } 0167 0168 std::vector<ComponentObject *> components = package->components(); 0169 sort(components); 0170 if (!components.empty()) { 0171 qDebug() << " COMPONENTS:"; 0172 } 0173 for (ComponentObject *component : components) { 0174 auto c_lock = component->readOnlyLock(); 0175 (void) c_lock; 0176 qDebug() << " " << component->qualifiedName(); 0177 } 0178 0179 qDebug(); 0180 } 0181 0182 static void printPackages(ObjectStore& session) 0183 { 0184 qDebug() << "PACKAGES:"; 0185 for (const auto& [_, package] : session.packages()) { 0186 (void) _; 0187 printPackage(package.get()); 0188 } 0189 } 0190 0191 static void printClass(TypeObject *klass) 0192 { 0193 auto lock = klass->readOnlyLock(); 0194 (void) lock; 0195 0196 qDebug() << " " << klass->qualifiedName(); 0197 0198 std::vector<FileObject *> files = klass->files(); 0199 if (!files.empty()) { 0200 qDebug() << " FILES:"; 0201 } 0202 for (const auto& file : files) { 0203 auto lockFile = file->readOnlyLock(); 0204 (void) lockFile; 0205 qDebug() << " " << file->qualifiedName(); 0206 } 0207 0208 const auto *nmspc = klass->parentNamespace(); 0209 if (nmspc) { 0210 qDebug() << " NAMESPACE: " << nmspc->qualifiedName(); 0211 } 0212 0213 const auto *pkg = klass->package(); 0214 if (pkg) { 0215 qDebug() << " PACKAGE: " << pkg->qualifiedName(); 0216 } 0217 0218 const auto *parentClass = klass->parent(); 0219 if (parentClass) { 0220 qDebug() << " PARENT CLASS: " << parentClass->qualifiedName(); 0221 } 0222 0223 // Is-A relationships 0224 std::vector<TypeObject *> isAs = klass->superclasses(); 0225 0226 if (!isAs.empty()) { 0227 qDebug() << " IS-A RELATIONSHPS:"; 0228 } 0229 for (TypeObject *superClass : isAs) { 0230 auto c_lock = superClass->readOnlyLock(); 0231 (void) c_lock; 0232 qDebug() << " " << superClass->qualifiedName(); 0233 } 0234 0235 std::vector<TypeObject *> usesInInters = klass->usesInTheInterface(); 0236 sort(usesInInters); 0237 if (!usesInInters.empty()) { 0238 qDebug() << " USES-IN-THE-INTERFACE RELATIONSHIPS:"; 0239 } 0240 for (const auto& dep : usesInInters) { 0241 qDebug() << " " << dep->qualifiedName(); 0242 } 0243 0244 std::vector<TypeObject *> usesInImpls = klass->usesInTheImplementation(); 0245 sort(usesInImpls); 0246 if (!usesInImpls.empty()) { 0247 qDebug() << " USES-IN-THE-IMPLEMENTATION RELATIONSHIPS:"; 0248 } 0249 for (const auto& dep : usesInImpls) { 0250 qDebug() << " " << dep->qualifiedName(); 0251 } 0252 0253 std::vector<MethodObject *> methods = klass->methods(); 0254 sort(methods); 0255 if (!methods.empty()) { 0256 qDebug() << " METHODS:"; 0257 } 0258 for (const auto& method : methods) { 0259 auto m_lock = method->readOnlyLock(); 0260 (void) m_lock; 0261 qDebug() << " " << method->qualifiedName(); 0262 } 0263 0264 std::vector<FieldObject *> fields = klass->fields(); 0265 sort(fields); 0266 if (!fields.empty()) { 0267 qDebug() << " FIELDS:"; 0268 } 0269 for (const auto& field : fields) { 0270 auto f_lock = field->readOnlyLock(); 0271 (void) f_lock; 0272 qDebug() << " " << field->qualifiedName(); 0273 } 0274 0275 qDebug(); 0276 } 0277 0278 static void printClasses(ObjectStore& session) 0279 { 0280 qDebug() << "CLASSES:"; 0281 for (const auto& [_, klass] : session.types()) { 0282 (void) _; 0283 printClass(klass.get()); 0284 } 0285 } 0286 0287 static void printDatabase(ObjectStore& session) 0288 { 0289 auto lock = session.readOnlyLock(); 0290 (void) lock; 0291 printFiles(session); 0292 printPackages(session); 0293 printClasses(session); 0294 } 0295 0296 int main(int argc, const char **argv) 0297 { 0298 const char *const prog = argv[0]; 0299 if (argc != 2) { 0300 printHelp(prog); 0301 return EXIT_FAILURE; 0302 } 0303 0304 const char *const arg = argv[1]; 0305 0306 if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { 0307 printHelp(prog); 0308 return EXIT_SUCCESS; 0309 } 0310 0311 if (!std::filesystem::is_regular_file(arg)) { 0312 qDebug() << arg << " is not a file"; 0313 return EXIT_FAILURE; 0314 } 0315 0316 lvtprj::ProjectFile projectFile; 0317 auto projectOpened = projectFile.open(arg); 0318 if (projectOpened.has_error()) { 0319 qDebug() << "Error opening project file" << projectOpened.error().errorMessage; 0320 return EXIT_FAILURE; 0321 } 0322 0323 lvtmdb::SociReader reader; 0324 ObjectStore store; 0325 auto res = store.readFromDatabase(reader, projectFile.codeDatabasePath().string()); 0326 if (res.has_error()) { 0327 qDebug() << "Error opening database: " << res.error().what << "\n"; 0328 return EXIT_FAILURE; 0329 } 0330 0331 printDatabase(store); 0332 0333 return EXIT_SUCCESS; 0334 }