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 }