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