File indexing completed on 2024-11-24 05:05:28
0001 /* 0002 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk> 0003 // SPDX-License-Identifier: Apache-2.0 0004 // 0005 // Licensed under the Apache License, Version 2.0 (the "License"); 0006 // you may not use this file except in compliance with the License. 0007 // You may obtain a copy of the License at 0008 // 0009 // http://www.apache.org/licenses/LICENSE-2.0 0010 // 0011 // Unless required by applicable law or agreed to in writing, software 0012 // distributed under the License is distributed on an "AS IS" BASIS, 0013 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0014 // See the License for the specific language governing permissions and 0015 // limitations under the License. 0016 */ 0017 0018 #include <ct_lvtmdb_componentobject.h> 0019 #include <ct_lvtmdb_packageobject.h> 0020 #include <flang/Frontend/CompilerInstance.h> 0021 #include <fortran/ct_lvtclp_physicalscanner.h> 0022 0023 #include <filesystem> 0024 #include <unordered_set> 0025 0026 namespace Codethink::lvtclp::fortran { 0027 0028 using namespace Fortran::parser; 0029 const char *const NON_LAKOSIAN_GROUP_NAME = "non-lakosian group"; 0030 0031 PhysicalParseAction::PhysicalParseAction(lvtmdb::ObjectStore& memDb): memDb(memDb) 0032 { 0033 } 0034 0035 lvtmdb::ComponentObject *addComponentForFile(lvtmdb::ObjectStore& memDb, std::filesystem::path const& filePath) 0036 { 0037 lvtmdb::ComponentObject *currentComponent = nullptr; 0038 memDb.withRWLock([&]() { 0039 auto qName = filePath.parent_path().stem(); 0040 0041 // TODO: Proper package handling. Currently assume all Fortran packages are "non-lakosian" 0042 auto *grp = memDb.getOrAddPackage( 0043 /*qualifiedName=*/NON_LAKOSIAN_GROUP_NAME, 0044 /*name=*/NON_LAKOSIAN_GROUP_NAME, 0045 /*diskPath=*/"", 0046 /*parent=*/nullptr, 0047 /*repository=*/nullptr); 0048 auto *package = memDb.getOrAddPackage( 0049 /*qualifiedName=*/qName, 0050 /*name=*/qName, 0051 /*diskPath=*/"", 0052 /*parent=*/grp, 0053 /*repository=*/nullptr); 0054 auto component = memDb.getOrAddComponent( 0055 /*qualifiedName=*/qName.string() + "/" + filePath.stem().string(), 0056 /*name=*/filePath.stem(), 0057 /*package=*/package); 0058 auto *file = memDb.getOrAddFile( 0059 /*qualifiedName=*/filePath.string(), 0060 /*name=*/filePath.string(), 0061 /*isHeader=*/false, 0062 /*hash=*/"", // TODO: Properly generate hash, if ever necessary 0063 /*package=*/package, 0064 /*component=*/component); 0065 assert(file); 0066 0067 component->withRWLock([&] { 0068 component->addFile(file); 0069 }); 0070 package->withRWLock([&] { 0071 package->addComponent(component); 0072 }); 0073 0074 currentComponent = component; 0075 }); 0076 assert(currentComponent); 0077 return currentComponent; 0078 } 0079 0080 void PhysicalParseAction::executeAction() 0081 { 0082 auto currentInputPath = std::filesystem::path{getCurrentFileOrBufferName().str()}; 0083 auto currentComponent = addComponentForFile(memDb, currentInputPath); 0084 0085 auto& allSources = getInstance().getAllCookedSources().allSources(); 0086 auto processSourceFileFrom = [&](Provenance const& p) { 0087 auto srcFile = allSources.GetSourceFile(p); 0088 if (srcFile == nullptr) { 0089 return; // Doesn't have associated source file 0090 } 0091 0092 auto dependencyPath = std::filesystem::path{srcFile->path()}; 0093 auto targetComponent = addComponentForFile(memDb, dependencyPath); 0094 lvtmdb::ComponentObject::addDependency(currentComponent, targetComponent); 0095 0096 auto srcLock = currentComponent->readOnlyLock(); 0097 auto trgLock = targetComponent->readOnlyLock(); 0098 auto srcParent = currentComponent->package(); 0099 auto trgParent = targetComponent->package(); 0100 while (srcParent && trgParent && srcParent != trgParent) { 0101 lvtmdb::PackageObject::addDependency(srcParent, trgParent); 0102 0103 auto srcParentLock = srcParent->readOnlyLock(); 0104 auto trgParentLock = trgParent->readOnlyLock(); 0105 srcParent = srcParent->parent(); 0106 trgParent = trgParent->parent(); 0107 } 0108 }; 0109 0110 auto interval = *allSources.GetFirstFileProvenance(); 0111 auto currProvenance = interval.start(); 0112 auto alreadyProcessed = std::unordered_set<const SourceFile *>{}; 0113 while (allSources.IsValid(currProvenance)) { 0114 auto provenance = interval.start(); 0115 auto srcFile = allSources.GetSourceFile(provenance); 0116 0117 if (!alreadyProcessed.contains(srcFile)) { 0118 processSourceFileFrom(provenance); 0119 alreadyProcessed.insert(srcFile); 0120 } 0121 0122 // TODO: NextAfter doesn't properly get the next interval, just the next position 0123 // with size 1. This means after the first interval, positions are incremented 0124 // by 1, and thus this algorithm is extremely dummy. 0125 interval = interval.NextAfter(); 0126 currProvenance = interval.start(); 0127 } 0128 } 0129 0130 } // namespace Codethink::lvtclp::fortran