2828#include " clang/Tooling/DependencyScanning/ModuleDepCollector.h"
2929#include " clang/Tooling/DependencyScanning/ScanAndUpdateArgs.h"
3030#include " clang/Tooling/Tooling.h"
31+ #include " llvm/ADT/IntrusiveRefCntPtr.h"
3132#include " llvm/ADT/ScopeExit.h"
3233#include " llvm/CAS/CASProvidingFileSystem.h"
3334#include " llvm/CAS/CachingOnDiskFileSystem.h"
3435#include " llvm/CAS/ObjectStore.h"
3536#include " llvm/Support/Allocator.h"
3637#include " llvm/Support/Error.h"
38+ #include " llvm/Support/MemoryBuffer.h"
3739#include " llvm/Support/PrefixMapper.h"
3840#include " llvm/TargetParser/Host.h"
3941#include < optional>
@@ -744,20 +746,43 @@ DependencyScanningWorker::getOrCreateFileManager() const {
744746 return new FileManager (FileSystemOptions (), BaseFS);
745747}
746748
747- llvm::Error DependencyScanningWorker::computeDependencies (
748- StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
749- DependencyConsumer &Consumer, DependencyActionController &Controller,
750- std::optional<StringRef> ModuleName) {
749+ static std::unique_ptr<DiagnosticOptions>
750+ createDiagOptions (const std::vector<std::string> &CommandLine) {
751751 std::vector<const char *> CLI;
752752 for (const std::string &Arg : CommandLine)
753753 CLI.push_back (Arg.c_str ());
754754 auto DiagOpts = CreateAndPopulateDiagOpts (CLI);
755755 sanitizeDiagOpts (*DiagOpts);
756+ return DiagOpts;
757+ }
756758
759+ llvm::Error DependencyScanningWorker::computeDependencies (
760+ StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
761+ DependencyConsumer &Consumer, DependencyActionController &Controller,
762+ std::optional<llvm::MemoryBufferRef> TUBuffer) {
757763 // Capture the emitted diagnostics and report them to the client
758764 // in the case of a failure.
759765 std::string DiagnosticOutput;
760766 llvm::raw_string_ostream DiagnosticsOS (DiagnosticOutput);
767+ auto DiagOpts = createDiagOptions (CommandLine);
768+ TextDiagnosticPrinter DiagPrinter (DiagnosticsOS, DiagOpts.release ());
769+
770+ if (computeDependencies (WorkingDirectory, CommandLine, Consumer, Controller,
771+ DiagPrinter, TUBuffer))
772+ return llvm::Error::success ();
773+ return llvm::make_error<llvm::StringError>(DiagnosticsOS.str (),
774+ llvm::inconvertibleErrorCode ());
775+ }
776+
777+ llvm::Error DependencyScanningWorker::computeDependencies (
778+ StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
779+ DependencyConsumer &Consumer, DependencyActionController &Controller,
780+ StringRef ModuleName) {
781+ // Capture the emitted diagnostics and report them to the client
782+ // in the case of a failure.
783+ std::string DiagnosticOutput;
784+ llvm::raw_string_ostream DiagnosticsOS (DiagnosticOutput);
785+ auto DiagOpts = createDiagOptions (CommandLine);
761786 TextDiagnosticPrinter DiagPrinter (DiagnosticsOS, DiagOpts.release ());
762787
763788 if (computeDependencies (WorkingDirectory, CommandLine, Consumer, Controller,
@@ -828,59 +853,18 @@ static bool createAndRunToolInvocation(
828853 return true ;
829854}
830855
831- bool DependencyScanningWorker::computeDependencies (
856+ bool DependencyScanningWorker::scanDependencies (
832857 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
833858 DependencyConsumer &Consumer, DependencyActionController &Controller,
834- DiagnosticConsumer &DC, std::optional<StringRef> ModuleName) {
835- // Reset what might have been modified in the previous worker invocation.
836- BaseFS->setCurrentWorkingDirectory (WorkingDirectory);
837-
838- std::optional<std::vector<std::string>> ModifiedCommandLine;
839- llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS;
840-
841- // If we're scanning based on a module name alone, we don't expect the client
842- // to provide us with an input file. However, the driver really wants to have
843- // one. Let's just make it up to make the driver happy.
844- if (ModuleName) {
845- auto OverlayFS =
846- llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
847- auto InMemoryFS =
848- llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
849- InMemoryFS->setCurrentWorkingDirectory (WorkingDirectory);
850-
851- SmallString<128 > FakeInputPath;
852- // TODO: We should retry the creation if the path already exists.
853- llvm::sys::fs::createUniquePath (*ModuleName + " -%%%%%%%%.input" ,
854- FakeInputPath,
855- /* MakeAbsolute=*/ false );
856- InMemoryFS->addFile (FakeInputPath, 0 , llvm::MemoryBuffer::getMemBuffer (" " ));
857-
858- llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay =
859- InMemoryFS;
860- // If we are using a CAS but not dependency CASFS, we need to provide the
861- // fake input file in a CASProvidingFS for include-tree.
862- if (CAS && !DepCASFS)
863- InMemoryOverlay =
864- llvm::cas::createCASProvidingFileSystem (CAS, std::move (InMemoryFS));
865-
866- OverlayFS->pushOverlay (InMemoryOverlay);
867- ModifiedFS = OverlayFS;
868- ModifiedCommandLine = CommandLine;
869- ModifiedCommandLine->emplace_back (FakeInputPath);
870- }
871-
872- const std::vector<std::string> &FinalCommandLine =
873- ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
874- auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;
875-
859+ DiagnosticConsumer &DC, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
860+ std::optional<StringRef> ModuleName) {
876861 auto FileMgr =
877- llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{}, FinalFS );
862+ llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{}, FS );
878863
879- std::vector<const char *> FinalCCommandLine (FinalCommandLine .size (), nullptr );
880- llvm::transform (FinalCommandLine, FinalCCommandLine .begin (),
864+ std::vector<const char *> CCommandLine (CommandLine .size (), nullptr );
865+ llvm::transform (CommandLine, CCommandLine .begin (),
881866 [](const std::string &Str) { return Str.c_str (); });
882-
883- auto DiagOpts = CreateAndPopulateDiagOpts (FinalCCommandLine);
867+ auto DiagOpts = CreateAndPopulateDiagOpts (CCommandLine);
884868 sanitizeDiagOpts (*DiagOpts);
885869 IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
886870 CompilerInstance::createDiagnostics (DiagOpts.release (), &DC,
@@ -902,12 +886,12 @@ bool DependencyScanningWorker::computeDependencies(
902886 /* DiagGenerationAsCompilation=*/ false , getCASOpts (),
903887 ModuleName);
904888 bool Success = false ;
905- if (FinalCommandLine [1 ] == " -cc1" ) {
906- Success = createAndRunToolInvocation (FinalCommandLine , Action, *FileMgr,
889+ if (CommandLine [1 ] == " -cc1" ) {
890+ Success = createAndRunToolInvocation (CommandLine , Action, *FileMgr,
907891 PCHContainerOps, *Diags, Consumer);
908892 } else {
909893 Success = forEachDriverJob (
910- FinalCommandLine , *Diags, *FileMgr, [&](const driver::Command &Cmd) {
894+ CommandLine , *Diags, *FileMgr, [&](const driver::Command &Cmd) {
911895 if (StringRef (Cmd.getCreator ().getName ()) != " clang" ) {
912896 // Non-clang command. Just pass through to the dependency
913897 // consumer.
@@ -935,10 +919,89 @@ bool DependencyScanningWorker::computeDependencies(
935919
936920 if (Success && !Action.hasScanned ())
937921 Diags->Report (diag::err_fe_expected_compiler_job)
938- << llvm::join (FinalCommandLine , " " );
922+ << llvm::join (CommandLine , " " );
939923 return Success && Action.hasScanned ();
940924}
941925
926+ bool DependencyScanningWorker::computeDependencies (
927+ StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
928+ DependencyConsumer &Consumer, DependencyActionController &Controller,
929+ DiagnosticConsumer &DC, std::optional<llvm::MemoryBufferRef> TUBuffer) {
930+ // Reset what might have been modified in the previous worker invocation.
931+ BaseFS->setCurrentWorkingDirectory (WorkingDirectory);
932+
933+ std::optional<std::vector<std::string>> ModifiedCommandLine;
934+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS;
935+
936+ // If we're scanning based on a module name alone, we don't expect the client
937+ // to provide us with an input file. However, the driver really wants to have
938+ // one. Let's just make it up to make the driver happy.
939+ if (TUBuffer) {
940+ auto OverlayFS =
941+ llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
942+ auto InMemoryFS =
943+ llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
944+ InMemoryFS->setCurrentWorkingDirectory (WorkingDirectory);
945+ auto InputPath = TUBuffer->getBufferIdentifier ();
946+ InMemoryFS->addFile (
947+ InputPath, 0 ,
948+ llvm::MemoryBuffer::getMemBufferCopy (TUBuffer->getBuffer ()));
949+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay =
950+ InMemoryFS;
951+ // If we are using a CAS but not dependency CASFS, we need to provide the
952+ // fake input file in a CASProvidingFS for include-tree.
953+ if (CAS && !DepCASFS)
954+ InMemoryOverlay =
955+ llvm::cas::createCASProvidingFileSystem (CAS, std::move (InMemoryFS));
956+
957+ OverlayFS->pushOverlay (InMemoryOverlay);
958+ ModifiedFS = OverlayFS;
959+ ModifiedCommandLine = CommandLine;
960+ ModifiedCommandLine->emplace_back (InputPath);
961+ }
962+
963+ const std::vector<std::string> &FinalCommandLine =
964+ ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
965+ auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;
966+
967+ return scanDependencies (WorkingDirectory, FinalCommandLine, Consumer,
968+ Controller, DC, FinalFS, /* ModuleName=*/ std::nullopt );
969+ }
970+
971+ bool DependencyScanningWorker::computeDependencies (
972+ StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
973+ DependencyConsumer &Consumer, DependencyActionController &Controller,
974+ DiagnosticConsumer &DC, StringRef ModuleName) {
975+ // Reset what might have been modified in the previous worker invocation.
976+ BaseFS->setCurrentWorkingDirectory (WorkingDirectory);
977+
978+ // If we're scanning based on a module name alone, we don't expect the client
979+ // to provide us with an input file. However, the driver really wants to have
980+ // one. Let's just make it up to make the driver happy.
981+ auto OverlayFS =
982+ llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
983+ auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
984+ InMemoryFS->setCurrentWorkingDirectory (WorkingDirectory);
985+ SmallString<128 > FakeInputPath;
986+ // TODO: We should retry the creation if the path already exists.
987+ llvm::sys::fs::createUniquePath (ModuleName + " -%%%%%%%%.input" , FakeInputPath,
988+ /* MakeAbsolute=*/ false );
989+ InMemoryFS->addFile (FakeInputPath, 0 , llvm::MemoryBuffer::getMemBuffer (" " ));
990+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay = InMemoryFS;
991+ // If we are using a CAS but not dependency CASFS, we need to provide the
992+ // fake input file in a CASProvidingFS for include-tree.
993+ if (CAS && !DepCASFS)
994+ InMemoryOverlay =
995+ llvm::cas::createCASProvidingFileSystem (CAS, std::move (InMemoryFS));
996+
997+ OverlayFS->pushOverlay (InMemoryOverlay);
998+ auto ModifiedCommandLine = CommandLine;
999+ ModifiedCommandLine.emplace_back (FakeInputPath);
1000+
1001+ return scanDependencies (WorkingDirectory, ModifiedCommandLine, Consumer,
1002+ Controller, DC, OverlayFS, ModuleName);
1003+ }
1004+
9421005DependencyActionController::~DependencyActionController () {}
9431006
9441007void DependencyScanningWorker::computeDependenciesFromCompilerInvocation (
0 commit comments