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