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

0001 // ct_lvtclp_logicalpostprocessutil.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 #include <ct_lvtclp_logicalpostprocessutil.h>
0021 
0022 #include <ct_lvtshr_fuzzyutil.h>
0023 
0024 #include <ct_lvtmdb_componentobject.h>
0025 #include <ct_lvtmdb_fileobject.h>
0026 #include <ct_lvtmdb_namespaceobject.h>
0027 #include <ct_lvtmdb_objectstore.h>
0028 #include <ct_lvtmdb_packageobject.h>
0029 #include <ct_lvtmdb_typeobject.h>
0030 
0031 #include <algorithm>
0032 #include <cctype>
0033 #include <iostream>
0034 #include <limits>
0035 #include <string>
0036 
0037 #include <QDebug>
0038 
0039 namespace {
0040 
0041 using namespace Codethink::lvtmdb;
0042 using Codethink::lvtshr::FuzzyUtil;
0043 
0044 // We already have the lock for the file, do not lock again.
0045 void setUdtFile(TypeObject *udt, FileObject *file, bool debugOutput)
0046 {
0047     ComponentObject *comp = nullptr;
0048     PackageObject *pkg = nullptr;
0049     file->withROLock([&] {
0050         pkg = file->package();
0051         comp = file->component();
0052     });
0053 
0054     udt->withRWLock([&] {
0055         udt->setUniqueFile(file);
0056         udt->setUniqueComponent(comp);
0057         udt->setPackage(pkg);
0058     });
0059 
0060     if (debugOutput) {
0061         auto fileLock = file->readOnlyLock();
0062         auto udtLock = udt->readOnlyLock();
0063         (void) fileLock;
0064         (void) udtLock;
0065 
0066         qDebug() << "Set file for " << QString::fromStdString(udt->qualifiedName()) << " to "
0067                  << QString::fromStdString(file->qualifiedName());
0068     }
0069 }
0070 
0071 bool fixUdt(TypeObject *udt, bool debugOutput)
0072 {
0073     int numFiles = 0;
0074     std::string loweredClassName;
0075     NamespaceObject *nmspc = nullptr;
0076 
0077     udt->withROLock([&] {
0078         numFiles = static_cast<int>(udt->files().size());
0079         loweredClassName = udt->name();
0080         nmspc = udt->parentNamespace();
0081     });
0082 
0083     if (numFiles == 0) {
0084         if (debugOutput) {
0085             auto udtLock = udt->readOnlyLock();
0086             (void) udtLock;
0087 
0088             qDebug() << "WARN: UDT " << QString::fromStdString(udt->qualifiedName()) << " has no source files";
0089         }
0090         // this is just a warning not a database killing error so return success
0091         return true;
0092     }
0093     if (numFiles == 1) {
0094         // class doesn't need fixing
0095         return true;
0096     }
0097 
0098     std::transform(loweredClassName.begin(), loweredClassName.end(), loweredClassName.begin(), ::tolower);
0099 
0100     FileObject *bestFile = nullptr;
0101     if (nmspc) {
0102         std::string expectedFilename;
0103         nmspc->withROLock([&] {
0104             expectedFilename = nmspc->name() + '_' + loweredClassName + ".";
0105         });
0106 
0107         bool found = false;
0108         udt->withRWLock([&] {
0109             for (FileObject *file : udt->files()) {
0110                 std::string thisFilename;
0111                 file->withROLock([&] {
0112                     thisFilename = file->name();
0113                 });
0114 
0115                 if (thisFilename.find(expectedFilename) != std::string::npos) {
0116                     // we found the right one! This should be the only file for that
0117                     // type
0118                     bestFile = file;
0119                     found = true;
0120                 }
0121             }
0122         });
0123         if (found) {
0124             setUdtFile(udt, bestFile, debugOutput);
0125             return true;
0126         }
0127     }
0128 
0129     // second try: which of the files has a name most similar to the class
0130     // name?
0131     size_t lowest_distance = std::numeric_limits<size_t>::max();
0132     udt->withROLock([&] {
0133         for (FileObject *file : udt->files()) {
0134             file->withROLock([&] {
0135                 size_t dist = FuzzyUtil::levensteinDistance(loweredClassName, file->name());
0136                 if (dist < lowest_distance) {
0137                     lowest_distance = dist;
0138                     bestFile = file;
0139                 }
0140             });
0141         }
0142     });
0143 
0144     setUdtFile(udt, bestFile, debugOutput);
0145 
0146     return true;
0147 }
0148 
0149 } // namespace
0150 
0151 namespace Codethink::lvtclp {
0152 
0153 bool LogicalPostProcessUtil::postprocess(lvtmdb::ObjectStore& store, bool debugOutput)
0154 {
0155     bool success = true;
0156 
0157     for (const auto& [_, udt] : store.types()) {
0158         (void) _;
0159         success &= fixUdt(udt.get(), debugOutput);
0160     }
0161 
0162     return success;
0163 }
0164 
0165 } // namespace Codethink::lvtclp