213 lines · c
1//===- DependencyScannerImpl.h - Implements dependency scanning *- C++ -*--===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNER_H10#define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNER_H11 12#include "clang/Driver/Compilation.h"13#include "clang/Frontend/CompilerInstance.h"14#include "clang/Frontend/CompilerInvocation.h"15#include "clang/Frontend/TextDiagnosticPrinter.h"16#include "clang/Serialization/ObjectFilePCHContainerReader.h"17#include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h"18#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"19 20namespace clang {21class DiagnosticConsumer;22 23namespace tooling {24namespace dependencies {25class DependencyScanningService;26class DependencyScanningWorker;27 28class DependencyConsumer;29class DependencyActionController;30class DependencyScanningWorkerFilesystem;31 32class DependencyScanningAction {33public:34 DependencyScanningAction(35 DependencyScanningService &Service, StringRef WorkingDirectory,36 DependencyConsumer &Consumer, DependencyActionController &Controller,37 IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS,38 std::optional<StringRef> ModuleName = std::nullopt)39 : Service(Service), WorkingDirectory(WorkingDirectory),40 Consumer(Consumer), Controller(Controller), DepFS(std::move(DepFS)) {}41 bool runInvocation(std::unique_ptr<CompilerInvocation> Invocation,42 IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,43 std::shared_ptr<PCHContainerOperations> PCHContainerOps,44 DiagnosticConsumer *DiagConsumer);45 46 bool hasScanned() const { return Scanned; }47 bool hasDiagConsumerFinished() const { return DiagConsumerFinished; }48 49 /// Take the cc1 arguments corresponding to the most recent invocation used50 /// with this action. Any modifications implied by the discovered dependencies51 /// will have already been applied.52 std::vector<std::string> takeLastCC1Arguments() {53 std::vector<std::string> Result;54 std::swap(Result, LastCC1Arguments); // Reset LastCC1Arguments to empty.55 return Result;56 }57 58private:59 void setLastCC1Arguments(CompilerInvocation &&CI) {60 if (MDC)61 MDC->applyDiscoveredDependencies(CI);62 LastCC1Arguments = CI.getCC1CommandLine();63 }64 65 DependencyScanningService &Service;66 StringRef WorkingDirectory;67 DependencyConsumer &Consumer;68 DependencyActionController &Controller;69 IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;70 std::optional<CompilerInstance> ScanInstanceStorage;71 std::shared_ptr<ModuleDepCollector> MDC;72 std::vector<std::string> LastCC1Arguments;73 bool Scanned = false;74 bool DiagConsumerFinished = false;75};76 77// Helper functions and data types.78std::unique_ptr<DiagnosticOptions>79createDiagOptions(ArrayRef<std::string> CommandLine);80 81struct DignosticsEngineWithDiagOpts {82 // We need to bound the lifetime of the DiagOpts used to create the83 // DiganosticsEngine with the DiagnosticsEngine itself.84 std::unique_ptr<DiagnosticOptions> DiagOpts;85 IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine;86 87 DignosticsEngineWithDiagOpts(ArrayRef<std::string> CommandLine,88 IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,89 DiagnosticConsumer &DC);90};91 92struct TextDiagnosticsPrinterWithOutput {93 // We need to bound the lifetime of the data that supports the DiagPrinter94 // with it together so they have the same lifetime.95 std::string DiagnosticOutput;96 llvm::raw_string_ostream DiagnosticsOS;97 std::unique_ptr<DiagnosticOptions> DiagOpts;98 TextDiagnosticPrinter DiagPrinter;99 100 TextDiagnosticsPrinterWithOutput(ArrayRef<std::string> CommandLine)101 : DiagnosticsOS(DiagnosticOutput),102 DiagOpts(createDiagOptions(CommandLine)),103 DiagPrinter(DiagnosticsOS, *DiagOpts) {}104};105 106std::pair<std::unique_ptr<driver::Driver>, std::unique_ptr<driver::Compilation>>107buildCompilation(ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags,108 IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,109 llvm::BumpPtrAllocator &Alloc);110 111std::unique_ptr<CompilerInvocation>112createCompilerInvocation(ArrayRef<std::string> CommandLine,113 DiagnosticsEngine &Diags);114 115std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::vector<std::string>>116initVFSForTUBufferScanning(IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,117 ArrayRef<std::string> CommandLine,118 StringRef WorkingDirectory,119 llvm::MemoryBufferRef TUBuffer);120 121std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,122 std::vector<std::string>>123initVFSForByNameScanning(IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,124 ArrayRef<std::string> CommandLine,125 StringRef WorkingDirectory, StringRef ModuleName);126 127bool initializeScanCompilerInstance(128 CompilerInstance &ScanInstance,129 IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,130 DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service,131 IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS);132 133SmallVector<StringRef>134getInitialStableDirs(const CompilerInstance &ScanInstance);135 136std::optional<PrebuiltModulesAttrsMap>137computePrebuiltModulesASTMap(CompilerInstance &ScanInstance,138 SmallVector<StringRef> &StableDirs);139 140std::unique_ptr<DependencyOutputOptions>141takeAndUpdateDependencyOutputOptionsFrom(CompilerInstance &ScanInstance);142 143/// Create the dependency collector that will collect the produced144/// dependencies. May return the created ModuleDepCollector depending145/// on the scanning format.146std::shared_ptr<ModuleDepCollector> initializeScanInstanceDependencyCollector(147 CompilerInstance &ScanInstance,148 std::unique_ptr<DependencyOutputOptions> DepOutputOpts,149 StringRef WorkingDirectory, DependencyConsumer &Consumer,150 DependencyScanningService &Service, CompilerInvocation &Inv,151 DependencyActionController &Controller,152 PrebuiltModulesAttrsMap PrebuiltModulesASTMap,153 llvm::SmallVector<StringRef> &StableDirs);154 155class CompilerInstanceWithContext {156 // Context157 DependencyScanningWorker &Worker;158 llvm::StringRef CWD;159 std::vector<std::string> CommandLine;160 161 // Context - file systems162 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS;163 164 // Context - Diagnostics engine.165 std::unique_ptr<TextDiagnosticsPrinterWithOutput> DiagPrinterWithOS;166 // DiagConsumer may points to DiagPrinterWithOS->DiagPrinter, or a custom167 // DiagnosticConsumer passed in from initialize.168 DiagnosticConsumer *DiagConsumer = nullptr;169 std::unique_ptr<DignosticsEngineWithDiagOpts> DiagEngineWithCmdAndOpts;170 171 // Context - compiler invocation172 // Compilation's command's arguments may be owned by Alloc when expanded from173 // response files, so we need to keep Alloc alive in the context.174 llvm::BumpPtrAllocator Alloc;175 std::unique_ptr<clang::driver::Driver> Driver;176 std::unique_ptr<clang::driver::Compilation> Compilation;177 std::unique_ptr<CompilerInvocation> OriginalInvocation;178 179 // Context - output options180 std::unique_ptr<DependencyOutputOptions> OutputOpts;181 182 // Context - stable directory handling183 llvm::SmallVector<StringRef> StableDirs;184 PrebuiltModulesAttrsMap PrebuiltModuleASTMap;185 186 // Compiler Instance187 std::unique_ptr<CompilerInstance> CIPtr;188 189 // Source location offset.190 int32_t SrcLocOffset = 0;191 192public:193 CompilerInstanceWithContext(DependencyScanningWorker &Worker, StringRef CWD,194 const std::vector<std::string> &CMD)195 : Worker(Worker), CWD(CWD), CommandLine(CMD) {};196 197 // The three methods below returns false when they fail, with the detail198 // accumulated in DiagConsumer.199 bool initialize(DiagnosticConsumer *DC);200 bool computeDependencies(StringRef ModuleName, DependencyConsumer &Consumer,201 DependencyActionController &Controller);202 bool finalize();203 204 // The method below turns the return status from the above methods205 // into an llvm::Error using a default DiagnosticConsumer.206 llvm::Error handleReturnStatus(bool Success);207};208} // namespace dependencies209} // namespace tooling210} // namespace clang211 212#endif213