File indexing completed on 2024-11-17 05:06:09

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 <fortran/ct_lvtclp_fortran_tool.h>
0019 #include <fortran/ct_lvtclp_logicalscanner.h>
0020 #include <fortran/ct_lvtclp_physicalscanner.h>
0021 
0022 #include <flang/Frontend/CompilerInstance.h>
0023 #include <flang/Frontend/FrontendActions.h>
0024 
0025 #include <clang/Driver/DriverDiagnostic.h>
0026 #include <clang/Tooling/JSONCompilationDatabase.h>
0027 #include <flang/Frontend/CompilerInstance.h>
0028 #include <flang/Frontend/CompilerInvocation.h>
0029 #include <flang/Frontend/TextDiagnosticBuffer.h>
0030 #include <flang/FrontendTool/Utils.h>
0031 #include <flang/Parser/parse-tree-visitor.h>
0032 #include <llvm/Option/Arg.h>
0033 #include <llvm/Option/ArgList.h>
0034 #include <llvm/Option/OptTable.h>
0035 #include <llvm/Support/TargetSelect.h>
0036 
0037 #include <iostream>
0038 #include <memory>
0039 
0040 using namespace Fortran::frontend;
0041 using namespace clang::tooling;
0042 
0043 namespace {
0044 
0045 void run(FrontendAction& act, CompileCommand const& cmd)
0046 {
0047     auto ext = std::filesystem::path{cmd.Filename}.extension().string();
0048     if (ext != ".f" && ext != ".for" && ext != ".f90" && ext != ".inc") {
0049         return;
0050     }
0051 
0052     std::unique_ptr<CompilerInstance> flang(new CompilerInstance());
0053     flang->createDiagnostics();
0054     if (!flang->hasDiagnostics()) {
0055         // TODO: Proper error management
0056         std::cout << "Could not create flang diagnostics.\n";
0057         return;
0058     }
0059 
0060     auto *diagsBuffer = new TextDiagnosticBuffer;
0061     llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(new clang::DiagnosticIDs());
0062     llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts = new clang::DiagnosticOptions();
0063     clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagsBuffer);
0064 
0065     auto args = std::vector<const char *>{};
0066     args.push_back(cmd.Filename.c_str());
0067     for (auto const& cmdLine : cmd.CommandLine) {
0068         if (cmdLine.starts_with("-I")) {
0069             args.push_back(cmdLine.c_str());
0070         }
0071     }
0072     bool success =
0073         CompilerInvocation::createFromArgs(flang->getInvocation(), llvm::ArrayRef<const char *>(args), diags);
0074 
0075     // Initialize targets first, so that --version shows registered targets.
0076     llvm::InitializeAllTargets();
0077     llvm::InitializeAllTargetMCs();
0078     llvm::InitializeAllAsmPrinters();
0079 
0080     diagsBuffer->flushDiagnostics(flang->getDiagnostics());
0081 
0082     if (!success) {
0083         // TODO: Proper error management
0084         std::cout << "Could not prepare the flang object.\n";
0085         return;
0086     }
0087 
0088     success = flang->executeAction(act);
0089     if (!success) {
0090         // TODO: Proper error management
0091         std::cout << "Action failed.\n";
0092         return;
0093     }
0094 
0095     // Delete output files to free Compiler Instance
0096     flang->clearOutputFiles(/*EraseFiles=*/false);
0097 }
0098 
0099 } // namespace
0100 
0101 namespace Codethink::lvtclp::fortran {
0102 
0103 Tool::Tool(std::unique_ptr<CompilationDatabase> compilationDatabase):
0104     compilationDatabase(std::move(compilationDatabase))
0105 {
0106 }
0107 
0108 std::unique_ptr<Tool> Tool::fromCompileCommands(std::filesystem::path const& compileCommandsJson)
0109 {
0110     auto errorMessage = std::string{};
0111     auto jsonDb = JSONCompilationDatabase::loadFromFile(compileCommandsJson.string(),
0112                                                         errorMessage,
0113                                                         clang::tooling::JSONCommandLineSyntax::AutoDetect);
0114     // TODO: Proper error management
0115     if (!errorMessage.empty()) {
0116         std::cout << "Tool::fromCompileCommands error: " << errorMessage;
0117         return nullptr;
0118     }
0119 
0120     return std::make_unique<Tool>(std::move(jsonDb));
0121 }
0122 
0123 bool Tool::runPhysical(bool skipScan)
0124 {
0125     auto action = PhysicalParseAction{this->memDb()};
0126     for (auto const& cmd : this->compilationDatabase->getAllCompileCommands()) {
0127         run(action, cmd);
0128     }
0129 
0130     return true;
0131 }
0132 
0133 bool Tool::runFull(bool skipPhysical)
0134 {
0135     if (!skipPhysical) {
0136         runPhysical(/*skipScan=*/false);
0137     }
0138     auto action = LogicalParseAction{this->memDb()};
0139     for (auto const& cmd : this->compilationDatabase->getAllCompileCommands()) {
0140         run(action, cmd);
0141     }
0142 
0143     return true;
0144 }
0145 
0146 lvtmdb::ObjectStore& Tool::getObjectStore()
0147 {
0148     return this->memDb();
0149 }
0150 
0151 void Tool::setSharedMemDb(std::shared_ptr<lvtmdb::ObjectStore> const& sharedMemDb)
0152 {
0153     this->sharedMemDb = sharedMemDb;
0154 }
0155 
0156 } // namespace Codethink::lvtclp::fortran