File indexing completed on 2024-05-19 05:42:03

0001 // ct_lvtclp_physicaldepscanner.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_clputil.h>
0021 #include <ct_lvtclp_physicaldepscanner.h>
0022 
0023 #include <ct_lvtclp_diagnostic_consumer.h>
0024 
0025 #include <clang/Frontend/CompilerInstance.h>
0026 #include <clang/Frontend/FrontendActions.h>
0027 
0028 namespace {
0029 
0030 using namespace Codethink;
0031 using namespace Codethink::lvtclp;
0032 
0033 class FrontendAction : public clang::PreprocessOnlyAction {
0034     // Per-thread processing using only the clang preprocessor
0035 
0036   private:
0037     lvtmdb::ObjectStore& d_memDb;
0038     std::filesystem::path d_prefix;
0039     std::vector<std::filesystem::path> d_nonLakosianDirs;
0040     std::vector<std::pair<std::string, std::string>> d_thirdPartyDirs;
0041     std::function<void(const std::string&)> d_filenameCallback;
0042     std::vector<llvm::GlobPattern> d_ignoreGlobs;
0043     std::optional<HeaderCallbacks::HeaderLocationCallback_f> d_headerLocationCallback;
0044 
0045   public:
0046     FrontendAction(lvtmdb::ObjectStore& memDb,
0047                    std::filesystem::path prefix,
0048                    std::vector<std::filesystem::path> nonLakosians,
0049                    std::vector<std::pair<std::string, std::string>> thirdPartyDirs,
0050                    std::function<void(const std::string&)> filenameCallback,
0051                    std::vector<llvm::GlobPattern> ignoreGlobs,
0052                    std::optional<HeaderCallbacks::HeaderLocationCallback_f> headerLocationCallback):
0053         d_memDb(memDb),
0054         d_prefix(std::move(prefix)),
0055         d_nonLakosianDirs(std::move(nonLakosians)),
0056         d_thirdPartyDirs(std::move(thirdPartyDirs)),
0057         d_filenameCallback(std::move(filenameCallback)),
0058         d_ignoreGlobs(std::move(ignoreGlobs)),
0059         d_headerLocationCallback(std::move(headerLocationCallback))
0060     {
0061     }
0062 
0063     ~FrontendAction() noexcept override = default;
0064 
0065     void ExecuteAction() override
0066     {
0067         auto realPathStr = getCurrentFile().str();
0068         if (ClpUtil::isFileIgnored(realPathStr, d_ignoreGlobs)) {
0069             return;
0070         }
0071 
0072         clang::CompilerInstance& compiler = getCompilerInstance();
0073         clang::Preprocessor& pp = compiler.getPreprocessor();
0074 
0075         pp.addPPCallbacks(std::make_unique<lvtclp::HeaderCallbacks>(&compiler.getSourceManager(),
0076                                                                     d_memDb,
0077                                                                     d_prefix,
0078                                                                     d_nonLakosianDirs,
0079                                                                     d_thirdPartyDirs,
0080                                                                     d_ignoreGlobs,
0081                                                                     d_headerLocationCallback));
0082 
0083         // try our best not to bail on compilation errors
0084         clang::FrontendOptions& fOpts = compiler.getFrontendOpts();
0085         fOpts.FixWhatYouCan = true;
0086         fOpts.FixAndRecompile = true;
0087         fOpts.FixToTemporaries = true;
0088         // skip parsing function bodies
0089         fOpts.SkipFunctionBodies = true;
0090 
0091         // Attempt to obliterate any -Werror options
0092         clang::DiagnosticOptions& dOpts = compiler.getDiagnosticOpts();
0093         dOpts.Warnings = {"-Wno-everything"};
0094 
0095         PreprocessOnlyAction::ExecuteAction();
0096     }
0097 
0098     bool BeginSourceFileAction(clang::CompilerInstance& ci) override
0099     {
0100         d_filenameCallback(getCurrentFile().str());
0101 
0102         auto realPathStr = getCurrentFile().str();
0103         if (ClpUtil::isFileIgnored(realPathStr, d_ignoreGlobs)) {
0104             return false;
0105         }
0106 
0107         return PreprocessOnlyAction::BeginSourceFileAction(ci);
0108     }
0109 };
0110 
0111 } // namespace
0112 
0113 namespace Codethink::lvtclp {
0114 
0115 struct DepScanActionFactory::Private {
0116     lvtmdb::ObjectStore& memDb;
0117     std::filesystem::path prefix;
0118     std::vector<std::filesystem::path> nonLakosianDirs;
0119     std::vector<std::pair<std::string, std::string>> thirdPartyDirs;
0120     std::function<void(const std::string&)> filenameCallback;
0121     std::vector<llvm::GlobPattern> ignoreGlobs;
0122     std::optional<HeaderCallbacks::HeaderLocationCallback_f> headerLocationCallback;
0123 
0124     Private(lvtmdb::ObjectStore& memDb,
0125             std::filesystem::path prefix,
0126             std::vector<std::filesystem::path> nonLakosians,
0127             std::vector<std::pair<std::string, std::string>> thirdPartyDirs,
0128             std::function<void(const std::string&)> filenameCallback,
0129             std::vector<llvm::GlobPattern> ignoreGlobs,
0130             std::optional<HeaderCallbacks::HeaderLocationCallback_f> headerLocationCallback):
0131         memDb(memDb),
0132         prefix(std::move(prefix)),
0133         nonLakosianDirs(std::move(nonLakosians)),
0134         thirdPartyDirs(std::move(thirdPartyDirs)),
0135         filenameCallback(std::move(filenameCallback)),
0136         ignoreGlobs(std::move(ignoreGlobs)),
0137         headerLocationCallback(std::move(headerLocationCallback))
0138     {
0139     }
0140 };
0141 
0142 DepScanActionFactory::DepScanActionFactory(
0143     lvtmdb::ObjectStore& memDb,
0144     const std::filesystem::path& prefix,
0145     const std::vector<std::filesystem::path>& nonLakosians,
0146     const std::vector<std::pair<std::string, std::string>>& thirdPartyDirs,
0147     std::function<void(const std::string&)> filenameCallback,
0148     std::vector<llvm::GlobPattern> ignoreGlobs,
0149     std::optional<HeaderCallbacks::HeaderLocationCallback_f> headerLocationCallback):
0150     d(std::make_unique<DepScanActionFactory::Private>(memDb,
0151                                                       prefix,
0152                                                       nonLakosians,
0153                                                       thirdPartyDirs,
0154                                                       std::move(filenameCallback),
0155                                                       std::move(ignoreGlobs),
0156                                                       std::move(headerLocationCallback)))
0157 {
0158 }
0159 
0160 DepScanActionFactory::~DepScanActionFactory() noexcept = default;
0161 
0162 std::unique_ptr<clang::FrontendAction> DepScanActionFactory::create()
0163 {
0164     return std::make_unique<FrontendAction>(d->memDb,
0165                                             d->prefix,
0166                                             d->nonLakosianDirs,
0167                                             d->thirdPartyDirs,
0168                                             d->filenameCallback,
0169                                             d->ignoreGlobs,
0170                                             d->headerLocationCallback);
0171 }
0172 
0173 } // namespace Codethink::lvtclp