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