diff options
Diffstat (limited to 'clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp')
| -rw-r--r-- | clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp | 167 |
1 files changed, 107 insertions, 60 deletions
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index d651ff23b387..7fdc49271791 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -133,6 +133,16 @@ deduceDepTarget(const std::string &OutputFile, return makeObjFileName(InputFiles.front().getFile()); } +/// Sanitize diagnostic options for dependency scan. +static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) { + // Don't print 'X warnings and Y errors generated'. + DiagOpts.ShowCarets = false; + // Don't write out diagnostic file. + DiagOpts.DiagnosticSerializationFile.clear(); + // Don't treat warnings as errors. + DiagOpts.Warnings.push_back("no-error"); +} + /// A clang tool that runs the preprocessor in a mode that's optimized for /// dependency scanning for the given compiler invocation. class DependencyScanningAction : public tooling::ToolAction { @@ -141,10 +151,11 @@ public: StringRef WorkingDirectory, DependencyConsumer &Consumer, llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS, ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings, - ScanningOutputFormat Format) + ScanningOutputFormat Format, bool OptimizeArgs, + llvm::Optional<StringRef> ModuleName = None) : WorkingDirectory(WorkingDirectory), Consumer(Consumer), - DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings), - Format(Format) {} + DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings), Format(Format), + OptimizeArgs(OptimizeArgs), ModuleName(ModuleName) {} bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, FileManager *FileMgr, @@ -154,39 +165,34 @@ public: CompilerInvocation OriginalInvocation(*Invocation); // Create a compiler instance to handle the actual work. - CompilerInstance Compiler(std::move(PCHContainerOps)); - Compiler.setInvocation(std::move(Invocation)); + CompilerInstance ScanInstance(std::move(PCHContainerOps)); + ScanInstance.setInvocation(std::move(Invocation)); - // Don't print 'X warnings and Y errors generated'. - Compiler.getDiagnosticOpts().ShowCarets = false; - // Don't write out diagnostic file. - Compiler.getDiagnosticOpts().DiagnosticSerializationFile.clear(); - // Don't treat warnings as errors. - Compiler.getDiagnosticOpts().Warnings.push_back("no-error"); // Create the compiler's actual diagnostics engine. - Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); - if (!Compiler.hasDiagnostics()) + sanitizeDiagOpts(ScanInstance.getDiagnosticOpts()); + ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); + if (!ScanInstance.hasDiagnostics()) return false; - Compiler.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath = true; + ScanInstance.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath = + true; FileMgr->getFileSystemOpts().WorkingDir = std::string(WorkingDirectory); - Compiler.setFileManager(FileMgr); - Compiler.createSourceManager(*FileMgr); + ScanInstance.setFileManager(FileMgr); + ScanInstance.createSourceManager(*FileMgr); llvm::StringSet<> PrebuiltModulesInputFiles; // Store the list of prebuilt module files into header search options. This // will prevent the implicit build to create duplicate modules and will // force reuse of the existing prebuilt module files instead. - if (!Compiler.getPreprocessorOpts().ImplicitPCHInclude.empty()) + if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty()) visitPrebuiltModule( - Compiler.getPreprocessorOpts().ImplicitPCHInclude, Compiler, - Compiler.getHeaderSearchOpts().PrebuiltModuleFiles, + ScanInstance.getPreprocessorOpts().ImplicitPCHInclude, ScanInstance, + ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles, PrebuiltModulesInputFiles, /*VisitInputFiles=*/DepFS != nullptr); // Use the dependency scanning optimized file system if requested to do so. if (DepFS) { - const CompilerInvocation &CI = Compiler.getInvocation(); DepFS->clearIgnoredFiles(); // Ignore any files that contributed to prebuilt modules. The implicit // build validates the modules by comparing the reported sizes of their @@ -197,20 +203,20 @@ public: // Add any filenames that were explicity passed in the build settings and // that might be opened, as we want to ensure we don't run source // minimization on them. - for (const auto &Entry : CI.getHeaderSearchOpts().UserEntries) - DepFS->ignoreFile(Entry.Path); - for (const auto &Entry : CI.getHeaderSearchOpts().VFSOverlayFiles) - DepFS->ignoreFile(Entry); + for (const auto &E : ScanInstance.getHeaderSearchOpts().UserEntries) + DepFS->ignoreFile(E.Path); + for (const auto &F : ScanInstance.getHeaderSearchOpts().VFSOverlayFiles) + DepFS->ignoreFile(F); // Support for virtual file system overlays on top of the caching // filesystem. FileMgr->setVirtualFileSystem(createVFSFromCompilerInvocation( - CI, Compiler.getDiagnostics(), DepFS)); + ScanInstance.getInvocation(), ScanInstance.getDiagnostics(), DepFS)); // Pass the skip mappings which should speed up excluded conditional block // skipping in the preprocessor. if (PPSkipMappings) - Compiler.getPreprocessorOpts() + ScanInstance.getPreprocessorOpts() .ExcludedConditionalDirectiveSkipMappings = PPSkipMappings; } @@ -222,35 +228,43 @@ public: // which ensures that the compiler won't create new dependency collectors, // and thus won't write out the extra '.d' files to disk. auto Opts = std::make_unique<DependencyOutputOptions>(); - std::swap(*Opts, Compiler.getInvocation().getDependencyOutputOpts()); + std::swap(*Opts, ScanInstance.getInvocation().getDependencyOutputOpts()); // We need at least one -MT equivalent for the generator of make dependency // files to work. if (Opts->Targets.empty()) - Opts->Targets = {deduceDepTarget(Compiler.getFrontendOpts().OutputFile, - Compiler.getFrontendOpts().Inputs)}; + Opts->Targets = { + deduceDepTarget(ScanInstance.getFrontendOpts().OutputFile, + ScanInstance.getFrontendOpts().Inputs)}; Opts->IncludeSystemHeaders = true; switch (Format) { case ScanningOutputFormat::Make: - Compiler.addDependencyCollector( + ScanInstance.addDependencyCollector( std::make_shared<DependencyConsumerForwarder>(std::move(Opts), Consumer)); break; case ScanningOutputFormat::Full: - Compiler.addDependencyCollector(std::make_shared<ModuleDepCollector>( - std::move(Opts), Compiler, Consumer, std::move(OriginalInvocation))); + ScanInstance.addDependencyCollector(std::make_shared<ModuleDepCollector>( + std::move(Opts), ScanInstance, Consumer, + std::move(OriginalInvocation), OptimizeArgs)); break; } // Consider different header search and diagnostic options to create // different modules. This avoids the unsound aliasing of module PCMs. // - // TODO: Implement diagnostic bucketing and header search pruning to reduce - // the impact of strict context hashing. - Compiler.getHeaderSearchOpts().ModulesStrictContextHash = true; + // TODO: Implement diagnostic bucketing to reduce the impact of strict + // context hashing. + ScanInstance.getHeaderSearchOpts().ModulesStrictContextHash = true; + + std::unique_ptr<FrontendAction> Action; + + if (ModuleName.hasValue()) + Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName); + else + Action = std::make_unique<ReadPCHAndPreprocessAction>(); - auto Action = std::make_unique<ReadPCHAndPreprocessAction>(); - const bool Result = Compiler.ExecuteAction(*Action); + const bool Result = ScanInstance.ExecuteAction(*Action); if (!DepFS) FileMgr->clearStatCache(); return Result; @@ -262,15 +276,15 @@ private: llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS; ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings; ScanningOutputFormat Format; + bool OptimizeArgs; + llvm::Optional<StringRef> ModuleName; }; } // end anonymous namespace DependencyScanningWorker::DependencyScanningWorker( DependencyScanningService &Service) - : Format(Service.getFormat()) { - DiagOpts = new DiagnosticOptions(); - + : Format(Service.getFormat()), OptimizeArgs(Service.canOptimizeArgs()) { PCHContainerOps = std::make_shared<PCHContainerOperations>(); PCHContainerOps->registerReader( std::make_unique<ObjectFilePCHContainerReader>()); @@ -279,7 +293,12 @@ DependencyScanningWorker::DependencyScanningWorker( PCHContainerOps->registerWriter( std::make_unique<ObjectFilePCHContainerWriter>()); - RealFS = llvm::vfs::createPhysicalFileSystem(); + auto OverlayFS = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>( + llvm::vfs::createPhysicalFileSystem()); + InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); + OverlayFS->pushOverlay(InMemoryFS); + RealFS = OverlayFS; + if (Service.canSkipExcludedPPRanges()) PPSkipMappings = std::make_unique<ExcludedPreprocessorDirectiveSkipMapping>(); @@ -290,36 +309,64 @@ DependencyScanningWorker::DependencyScanningWorker( Files = new FileManager(FileSystemOptions(), RealFS); } -static llvm::Error runWithDiags( - DiagnosticOptions *DiagOpts, - llvm::function_ref<bool(DiagnosticConsumer &DC)> BodyShouldSucceed) { +static llvm::Error +runWithDiags(DiagnosticOptions *DiagOpts, + llvm::function_ref<bool(DiagnosticConsumer &, DiagnosticOptions &)> + BodyShouldSucceed) { + sanitizeDiagOpts(*DiagOpts); + // Capture the emitted diagnostics and report them to the client // in the case of a failure. std::string DiagnosticOutput; llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts); - if (BodyShouldSucceed(DiagPrinter)) + if (BodyShouldSucceed(DiagPrinter, *DiagOpts)) return llvm::Error::success(); return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(), llvm::inconvertibleErrorCode()); } llvm::Error DependencyScanningWorker::computeDependencies( - const std::string &Input, StringRef WorkingDirectory, - const CompilationDatabase &CDB, DependencyConsumer &Consumer) { + StringRef WorkingDirectory, const std::vector<std::string> &CommandLine, + DependencyConsumer &Consumer, llvm::Optional<StringRef> ModuleName) { + // Reset what might have been modified in the previous worker invocation. RealFS->setCurrentWorkingDirectory(WorkingDirectory); - return runWithDiags(DiagOpts.get(), [&](DiagnosticConsumer &DC) { - /// Create the tool that uses the underlying file system to ensure that any - /// file system requests that are made by the driver do not go through the - /// dependency scanning filesystem. - tooling::ClangTool Tool(CDB, Input, PCHContainerOps, RealFS, Files); - Tool.clearArgumentsAdjusters(); - Tool.setRestoreWorkingDir(false); - Tool.setPrintErrorMessage(false); - Tool.setDiagnosticConsumer(&DC); - DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS, - PPSkipMappings.get(), Format); - return !Tool.run(&Action); - }); + if (Files) + Files->setVirtualFileSystem(RealFS); + + llvm::IntrusiveRefCntPtr<FileManager> CurrentFiles = + Files ? Files : new FileManager(FileSystemOptions(), RealFS); + + Optional<std::vector<std::string>> ModifiedCommandLine; + if (ModuleName.hasValue()) { + ModifiedCommandLine = CommandLine; + InMemoryFS->addFile(*ModuleName, 0, llvm::MemoryBuffer::getMemBuffer("")); + ModifiedCommandLine->emplace_back(*ModuleName); + } + + const std::vector<std::string> &FinalCommandLine = + ModifiedCommandLine ? *ModifiedCommandLine : CommandLine; + + std::vector<const char *> FinalCCommandLine(CommandLine.size(), nullptr); + llvm::transform(CommandLine, FinalCCommandLine.begin(), + [](const std::string &Str) { return Str.c_str(); }); + + return runWithDiags(CreateAndPopulateDiagOpts(FinalCCommandLine).release(), + [&](DiagnosticConsumer &DC, DiagnosticOptions &DiagOpts) { + DependencyScanningAction Action( + WorkingDirectory, Consumer, DepFS, + PPSkipMappings.get(), Format, OptimizeArgs, + ModuleName); + // Create an invocation that uses the underlying file + // system to ensure that any file system requests that + // are made by the driver do not go through the + // dependency scanning filesystem. + ToolInvocation Invocation(FinalCommandLine, &Action, + CurrentFiles.get(), + PCHContainerOps); + Invocation.setDiagnosticConsumer(&DC); + Invocation.setDiagnosticOptions(&DiagOpts); + return Invocation.run(); + }); } |
