2424#include " clang/Tooling/DependencyScanning/DependencyScanningService.h"
2525#include " clang/Tooling/DependencyScanning/ModuleDepCollector.h"
2626#include " clang/Tooling/Tooling.h"
27+ #include " llvm/ADT/IntrusiveRefCntPtr.h"
2728#include " llvm/ADT/ScopeExit.h"
2829#include " llvm/Support/Allocator.h"
2930#include " llvm/Support/Error.h"
31+ #include " llvm/Support/MemoryBuffer.h"
3032#include " llvm/TargetParser/Host.h"
3133#include < optional>
3234
@@ -521,20 +523,43 @@ DependencyScanningWorker::DependencyScanningWorker(
521523 }
522524}
523525
524- llvm::Error DependencyScanningWorker::computeDependencies (
525- StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
526- DependencyConsumer &Consumer, DependencyActionController &Controller,
527- std::optional<StringRef> ModuleName) {
526+ static std::unique_ptr<DiagnosticOptions>
527+ createDiagOptions (const std::vector<std::string> &CommandLine) {
528528 std::vector<const char *> CLI;
529529 for (const std::string &Arg : CommandLine)
530530 CLI.push_back (Arg.c_str ());
531531 auto DiagOpts = CreateAndPopulateDiagOpts (CLI);
532532 sanitizeDiagOpts (*DiagOpts);
533+ return DiagOpts;
534+ }
535+
536+ llvm::Error DependencyScanningWorker::computeDependencies (
537+ StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
538+ DependencyConsumer &Consumer, DependencyActionController &Controller,
539+ std::optional<llvm::MemoryBufferRef> TUBuffer) {
540+ // Capture the emitted diagnostics and report them to the client
541+ // in the case of a failure.
542+ std::string DiagnosticOutput;
543+ llvm::raw_string_ostream DiagnosticsOS (DiagnosticOutput);
544+ auto DiagOpts = createDiagOptions (CommandLine);
545+ TextDiagnosticPrinter DiagPrinter (DiagnosticsOS, DiagOpts.release ());
533546
547+ if (computeDependencies (WorkingDirectory, CommandLine, Consumer, Controller,
548+ DiagPrinter, TUBuffer))
549+ return llvm::Error::success ();
550+ return llvm::make_error<llvm::StringError>(DiagnosticsOS.str (),
551+ llvm::inconvertibleErrorCode ());
552+ }
553+
554+ llvm::Error DependencyScanningWorker::computeDependencies (
555+ StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
556+ DependencyConsumer &Consumer, DependencyActionController &Controller,
557+ StringRef ModuleName) {
534558 // Capture the emitted diagnostics and report them to the client
535559 // in the case of a failure.
536560 std::string DiagnosticOutput;
537561 llvm::raw_string_ostream DiagnosticsOS (DiagnosticOutput);
562+ auto DiagOpts = createDiagOptions (CommandLine);
538563 TextDiagnosticPrinter DiagPrinter (DiagnosticsOS, DiagOpts.release ());
539564
540565 if (computeDependencies (WorkingDirectory, CommandLine, Consumer, Controller,
@@ -604,54 +629,22 @@ static bool createAndRunToolInvocation(
604629 return true ;
605630}
606631
607- bool DependencyScanningWorker::computeDependencies (
632+ bool DependencyScanningWorker::scanDependencies (
608633 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
609634 DependencyConsumer &Consumer, DependencyActionController &Controller,
610- DiagnosticConsumer &DC, std::optional<StringRef> ModuleName) {
611- // Reset what might have been modified in the previous worker invocation.
612- BaseFS->setCurrentWorkingDirectory (WorkingDirectory);
613-
614- std::optional<std::vector<std::string>> ModifiedCommandLine;
615- llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS;
616-
617- // If we're scanning based on a module name alone, we don't expect the client
618- // to provide us with an input file. However, the driver really wants to have
619- // one. Let's just make it up to make the driver happy.
620- if (ModuleName) {
621- auto OverlayFS =
622- llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
623- auto InMemoryFS =
624- llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
625- InMemoryFS->setCurrentWorkingDirectory (WorkingDirectory);
626- OverlayFS->pushOverlay (InMemoryFS);
627- ModifiedFS = OverlayFS;
628-
629- SmallString<128 > FakeInputPath;
630- // TODO: We should retry the creation if the path already exists.
631- llvm::sys::fs::createUniquePath (*ModuleName + " -%%%%%%%%.input" ,
632- FakeInputPath,
633- /* MakeAbsolute=*/ false );
634- InMemoryFS->addFile (FakeInputPath, 0 , llvm::MemoryBuffer::getMemBuffer (" " ));
635-
636- ModifiedCommandLine = CommandLine;
637- ModifiedCommandLine->emplace_back (FakeInputPath);
638- }
639-
640- const std::vector<std::string> &FinalCommandLine =
641- ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
642- auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;
643-
635+ DiagnosticConsumer &DC, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
636+ std::optional<StringRef> ModuleName) {
644637 auto FileMgr =
645- llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{}, FinalFS );
638+ llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{}, FS );
646639
647- std::vector<const char *> FinalCCommandLine (FinalCommandLine .size (), nullptr );
648- llvm::transform (FinalCommandLine, FinalCCommandLine .begin (),
640+ std::vector<const char *> CCommandLine (CommandLine .size (), nullptr );
641+ llvm::transform (CommandLine, CCommandLine .begin (),
649642 [](const std::string &Str) { return Str.c_str (); });
650-
651- auto DiagOpts = CreateAndPopulateDiagOpts (FinalCCommandLine);
643+ auto DiagOpts = CreateAndPopulateDiagOpts (CCommandLine);
652644 sanitizeDiagOpts (*DiagOpts);
653645 IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
654- CompilerInstance::createDiagnostics (*FinalFS, DiagOpts.release (), &DC,
646+ CompilerInstance::createDiagnostics (FileMgr->getVirtualFileSystem (),
647+ DiagOpts.release (), &DC,
655648 /* ShouldOwnClient=*/ false );
656649
657650 // Although `Diagnostics` are used only for command-line parsing, the
@@ -667,12 +660,12 @@ bool DependencyScanningWorker::computeDependencies(
667660 DisableFree, ModuleName);
668661
669662 bool Success = false ;
670- if (FinalCommandLine [1 ] == " -cc1" ) {
671- Success = createAndRunToolInvocation (FinalCommandLine , Action, *FileMgr,
663+ if (CommandLine [1 ] == " -cc1" ) {
664+ Success = createAndRunToolInvocation (CommandLine , Action, *FileMgr,
672665 PCHContainerOps, *Diags, Consumer);
673666 } else {
674667 Success = forEachDriverJob (
675- FinalCommandLine , *Diags, *FileMgr, [&](const driver::Command &Cmd) {
668+ CommandLine , *Diags, *FileMgr, [&](const driver::Command &Cmd) {
676669 if (StringRef (Cmd.getCreator ().getName ()) != " clang" ) {
677670 // Non-clang command. Just pass through to the dependency
678671 // consumer.
@@ -699,8 +692,77 @@ bool DependencyScanningWorker::computeDependencies(
699692
700693 if (Success && !Action.hasScanned ())
701694 Diags->Report (diag::err_fe_expected_compiler_job)
702- << llvm::join (FinalCommandLine , " " );
695+ << llvm::join (CommandLine , " " );
703696 return Success && Action.hasScanned ();
704697}
705698
699+ bool DependencyScanningWorker::computeDependencies (
700+ StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
701+ DependencyConsumer &Consumer, DependencyActionController &Controller,
702+ DiagnosticConsumer &DC, std::optional<llvm::MemoryBufferRef> TUBuffer) {
703+ // Reset what might have been modified in the previous worker invocation.
704+ BaseFS->setCurrentWorkingDirectory (WorkingDirectory);
705+
706+ std::optional<std::vector<std::string>> ModifiedCommandLine;
707+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS;
708+
709+ // If we're scanning based on a module name alone, we don't expect the client
710+ // to provide us with an input file. However, the driver really wants to have
711+ // one. Let's just make it up to make the driver happy.
712+ if (TUBuffer) {
713+ auto OverlayFS =
714+ llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
715+ auto InMemoryFS =
716+ llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
717+ InMemoryFS->setCurrentWorkingDirectory (WorkingDirectory);
718+ auto InputPath = TUBuffer->getBufferIdentifier ();
719+ InMemoryFS->addFile (
720+ InputPath, 0 ,
721+ llvm::MemoryBuffer::getMemBufferCopy (TUBuffer->getBuffer ()));
722+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay =
723+ InMemoryFS;
724+
725+ OverlayFS->pushOverlay (InMemoryOverlay);
726+ ModifiedFS = OverlayFS;
727+ ModifiedCommandLine = CommandLine;
728+ ModifiedCommandLine->emplace_back (InputPath);
729+ }
730+
731+ const std::vector<std::string> &FinalCommandLine =
732+ ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
733+ auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;
734+
735+ return scanDependencies (WorkingDirectory, FinalCommandLine, Consumer,
736+ Controller, DC, FinalFS, /* ModuleName=*/ std::nullopt );
737+ }
738+
739+ bool DependencyScanningWorker::computeDependencies (
740+ StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
741+ DependencyConsumer &Consumer, DependencyActionController &Controller,
742+ DiagnosticConsumer &DC, StringRef ModuleName) {
743+ // Reset what might have been modified in the previous worker invocation.
744+ BaseFS->setCurrentWorkingDirectory (WorkingDirectory);
745+
746+ // If we're scanning based on a module name alone, we don't expect the client
747+ // to provide us with an input file. However, the driver really wants to have
748+ // one. Let's just make it up to make the driver happy.
749+ auto OverlayFS =
750+ llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
751+ auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
752+ InMemoryFS->setCurrentWorkingDirectory (WorkingDirectory);
753+ SmallString<128 > FakeInputPath;
754+ // TODO: We should retry the creation if the path already exists.
755+ llvm::sys::fs::createUniquePath (ModuleName + " -%%%%%%%%.input" , FakeInputPath,
756+ /* MakeAbsolute=*/ false );
757+ InMemoryFS->addFile (FakeInputPath, 0 , llvm::MemoryBuffer::getMemBuffer (" " ));
758+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay = InMemoryFS;
759+
760+ OverlayFS->pushOverlay (InMemoryOverlay);
761+ auto ModifiedCommandLine = CommandLine;
762+ ModifiedCommandLine.emplace_back (FakeInputPath);
763+
764+ return scanDependencies (WorkingDirectory, ModifiedCommandLine, Consumer,
765+ Controller, DC, OverlayFS, ModuleName);
766+ }
767+
706768DependencyActionController::~DependencyActionController () {}
0 commit comments