99#include  " DependencyScannerImpl.h" 
1010#include  " clang/Basic/DiagnosticFrontend.h" 
1111#include  " clang/Basic/DiagnosticSerialization.h" 
12+ #include  " clang/Driver/Driver.h" 
1213#include  " clang/Frontend/FrontendActions.h" 
1314#include  " clang/Tooling/DependencyScanning/DependencyScanningWorker.h" 
15+ #include  " llvm/TargetParser/Host.h" 
1416
1517using  namespace  clang ; 
1618using  namespace  tooling ; 
@@ -332,11 +334,9 @@ class ScanningDependencyDirectivesGetter : public DependencyDirectivesGetter {
332334    return  DepFS->getDirectiveTokens (File.getName ());
333335  }
334336};
335- } //  namespace
336337
337338// / Sanitize diagnostic options for dependency scan.
338- void  clang::tooling::dependencies::sanitizeDiagOpts (
339-     DiagnosticOptions &DiagOpts) {
339+ void  sanitizeDiagOpts (DiagnosticOptions &DiagOpts) {
340340  //  Don't print 'X warnings and Y errors generated'.
341341  DiagOpts.ShowCarets  = false ;
342342  //  Don't write out diagnostic file.
@@ -355,44 +355,146 @@ void clang::tooling::dependencies::sanitizeDiagOpts(
355355        .Default (true );
356356  });
357357}
358+ } //  namespace
358359
359- bool   DependencyScanningAction::runInvocation ( 
360-      std::shared_ptr<CompilerInvocation> Invocation, 
361-     IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, 
362-      std::shared_ptr<PCHContainerOperations> PCHContainerOps, 
363-     DiagnosticConsumer *DiagConsumer) { 
364-   //  Making sure that we canonicalize the defines before we create the deep 
365-   //  copy to avoid unnecessary variants in the scanner and in the resulting 
366-   //  explicit command lines. 
367-   if  ( any (Service. getOptimizeArgs () & ScanningOptimizations::Macros)) 
368-      canonicalizeDefines (Invocation-> getPreprocessorOpts ()); 
360+ namespace   clang ::tooling::dependencies { 
361+ std::unique_ptr<DiagnosticOptions> 
362+ createDiagOptions (ArrayRef<std::string> CommandLine) { 
363+   std::vector< const   char  *> CLI; 
364+   for  ( const  std::string &Arg : CommandLine) 
365+     CLI. push_back (Arg. c_str ()); 
366+   auto  DiagOpts =  CreateAndPopulateDiagOpts (CLI); 
367+   sanitizeDiagOpts (*DiagOpts); 
368+   return  DiagOpts; 
369+ } 
369370
370-   //  Make a deep copy of the original Clang invocation.
371-   CompilerInvocation OriginalInvocation (*Invocation);
371+ DignosticsEngineWithDiagOpts::DignosticsEngineWithDiagOpts (
372+     ArrayRef<std::string> CommandLine,
373+     IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, DiagnosticConsumer &DC) {
374+   std::vector<const  char  *> CCommandLine (CommandLine.size (), nullptr );
375+   llvm::transform (CommandLine, CCommandLine.begin (),
376+                   [](const  std::string &Str) { return  Str.c_str (); });
377+   DiagOpts = CreateAndPopulateDiagOpts (CCommandLine);
378+   sanitizeDiagOpts (*DiagOpts);
379+   DiagEngine = CompilerInstance::createDiagnostics (*FS, *DiagOpts, &DC,
380+                                                    /* ShouldOwnClient=*/ false );
381+ }
372382
373-   if  (Scanned) {
374-     //  Scanning runs once for the first -cc1 invocation in a chain of driver
375-     //  jobs. For any dependent jobs, reuse the scanning result and just
376-     //  update the LastCC1Arguments to correspond to the new invocation.
377-     //  FIXME: to support multi-arch builds, each arch requires a separate scan
378-     setLastCC1Arguments (std::move (OriginalInvocation));
379-     return  true ;
383+ std::pair<std::unique_ptr<driver::Driver>, std::unique_ptr<driver::Compilation>>
384+ buildCompilation (ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags,
385+                  IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
386+   SmallVector<const  char  *, 256 > Argv;
387+   Argv.reserve (ArgStrs.size ());
388+   for  (const  std::string &Arg : ArgStrs)
389+     Argv.push_back (Arg.c_str ());
390+ 
391+   std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
392+       Argv[0 ], llvm::sys::getDefaultTargetTriple (), Diags,
393+       " clang LLVM compiler" 
394+   Driver->setTitle (" clang_based_tool" 
395+ 
396+   llvm::BumpPtrAllocator Alloc;
397+   bool  CLMode = driver::IsClangCL (
398+       driver::getDriverMode (Argv[0 ], ArrayRef (Argv).slice (1 )));
399+ 
400+   if  (llvm::Error E =
401+           driver::expandResponseFiles (Argv, CLMode, Alloc, FS.get ())) {
402+     Diags.Report (diag::err_drv_expand_response_file)
403+         << llvm::toString (std::move (E));
404+     return  std::make_pair (nullptr , nullptr );
380405  }
381406
382-   Scanned = true ;
407+   std::unique_ptr<driver::Compilation> Compilation (
408+       Driver->BuildCompilation (Argv));
409+   if  (!Compilation)
410+     return  std::make_pair (nullptr , nullptr );
383411
384-   //  Create a compiler instance to handle the actual work.
385-   auto  ModCache = makeInProcessModuleCache (Service.getModuleCacheEntries ());
386-   ScanInstanceStorage.emplace (std::move (Invocation), std::move (PCHContainerOps),
387-                               ModCache.get ());
388-   CompilerInstance &ScanInstance = *ScanInstanceStorage;
412+   if  (Compilation->containsError ())
413+     return  std::make_pair (nullptr , nullptr );
414+ 
415+   return  std::make_pair (std::move (Driver), std::move (Compilation));
416+ }
417+ 
418+ std::unique_ptr<CompilerInvocation>
419+ createCompilerInvocation (ArrayRef<std::string> CommandLine,
420+                          DiagnosticsEngine &Diags) {
421+   llvm::opt::ArgStringList Argv;
422+   for  (const  std::string &Str : ArrayRef (CommandLine).drop_front ())
423+     Argv.push_back (Str.c_str ());
424+ 
425+   auto  Invocation = std::make_unique<CompilerInvocation>();
426+   if  (!CompilerInvocation::CreateFromArgs (*Invocation, Argv, Diags)) {
427+     //  FIXME: Should we just go on like cc1_main does?
428+     return  nullptr ;
429+   }
430+   return  Invocation;
431+ }
432+ 
433+ std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::vector<std::string>>
434+ initVFSForTUBuferScanning (IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
435+                           ArrayRef<std::string> CommandLine,
436+                           StringRef WorkingDirectory,
437+                           llvm::MemoryBufferRef TUBuffer) {
438+   //  Reset what might have been modified in the previous worker invocation.
439+   BaseFS->setCurrentWorkingDirectory (WorkingDirectory);
440+ 
441+   IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS;
442+   auto  OverlayFS =
443+       llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
444+   auto  InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
445+   InMemoryFS->setCurrentWorkingDirectory (WorkingDirectory);
446+   auto  InputPath = TUBuffer.getBufferIdentifier ();
447+   InMemoryFS->addFile (
448+       InputPath, 0 , llvm::MemoryBuffer::getMemBufferCopy (TUBuffer.getBuffer ()));
449+   IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay = InMemoryFS;
450+ 
451+   OverlayFS->pushOverlay (InMemoryOverlay);
452+   ModifiedFS = OverlayFS;
453+   std::vector<std::string> ModifiedCommandLine (CommandLine);
454+   ModifiedCommandLine.emplace_back (InputPath);
455+ 
456+   return  std::make_pair (ModifiedFS, ModifiedCommandLine);
457+ }
458+ 
459+ std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::vector<std::string>>
460+ initVFSForByNameScanning (IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
461+                          ArrayRef<std::string> CommandLine,
462+                          StringRef WorkingDirectory, StringRef ModuleName) {
463+   //  Reset what might have been modified in the previous worker invocation.
464+   BaseFS->setCurrentWorkingDirectory (WorkingDirectory);
465+ 
466+   //  If we're scanning based on a module name alone, we don't expect the client
467+   //  to provide us with an input file. However, the driver really wants to have
468+   //  one. Let's just make it up to make the driver happy.
469+   auto  OverlayFS =
470+       llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
471+   auto  InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
472+   InMemoryFS->setCurrentWorkingDirectory (WorkingDirectory);
473+   SmallString<128 > FakeInputPath;
474+   //  TODO: We should retry the creation if the path already exists.
475+   llvm::sys::fs::createUniquePath (ModuleName + " -%%%%%%%%.input" 
476+                                   /* MakeAbsolute=*/ false );
477+   InMemoryFS->addFile (FakeInputPath, 0 , llvm::MemoryBuffer::getMemBuffer (" " 
478+   IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay = InMemoryFS;
479+   OverlayFS->pushOverlay (InMemoryOverlay);
480+ 
481+   std::vector<std::string> ModifiedCommandLine (CommandLine);
482+   ModifiedCommandLine.emplace_back (FakeInputPath);
483+ 
484+   return  std::make_pair (OverlayFS, ModifiedCommandLine);
485+ }
486+ 
487+ bool  initializeScanCompilerInstance (
488+     CompilerInstance &ScanInstance,
489+     IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
490+     DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service,
491+     IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS) {
389492  ScanInstance.setBuildingModule (false );
390493
391494  ScanInstance.createVirtualFileSystem (FS, DiagConsumer);
392495
393496  //  Create the compiler's actual diagnostics engine.
394497  sanitizeDiagOpts (ScanInstance.getDiagnosticOpts ());
395-   assert (!DiagConsumerFinished && " attempt to reuse finished consumer" 
396498  ScanInstance.createDiagnostics (DiagConsumer, /* ShouldOwnClient=*/ false );
397499  if  (!ScanInstance.hasDiagnostics ())
398500    return  false ;
@@ -435,14 +537,39 @@ bool DependencyScanningAction::runInvocation(
435537
436538  ScanInstance.createSourceManager ();
437539
540+   //  Consider different header search and diagnostic options to create
541+   //  different modules. This avoids the unsound aliasing of module PCMs.
542+   // 
543+   //  TODO: Implement diagnostic bucketing to reduce the impact of strict
544+   //  context hashing.
545+   ScanInstance.getHeaderSearchOpts ().ModulesStrictContextHash  = true ;
546+   ScanInstance.getHeaderSearchOpts ().ModulesSerializeOnlyPreprocessor  = true ;
547+   ScanInstance.getHeaderSearchOpts ().ModulesSkipDiagnosticOptions  = true ;
548+   ScanInstance.getHeaderSearchOpts ().ModulesSkipHeaderSearchPaths  = true ;
549+   ScanInstance.getHeaderSearchOpts ().ModulesSkipPragmaDiagnosticMappings  = true ;
550+   ScanInstance.getHeaderSearchOpts ().ModulesForceValidateUserHeaders  = false ;
551+ 
552+   //  Avoid some checks and module map parsing when loading PCM files.
553+   ScanInstance.getPreprocessorOpts ().ModulesCheckRelocated  = false ;
554+ 
555+   return  true ;
556+ }
557+ 
558+ llvm::SmallVector<StringRef>
559+ getInitialStableDirs (const  CompilerInstance &ScanInstance) {
438560  //  Create a collection of stable directories derived from the ScanInstance
439561  //  for determining whether module dependencies would fully resolve from
440562  //  those directories.
441563  llvm::SmallVector<StringRef> StableDirs;
442564  const  StringRef Sysroot = ScanInstance.getHeaderSearchOpts ().Sysroot ;
443565  if  (!Sysroot.empty () && (llvm::sys::path::root_directory (Sysroot) != Sysroot))
444566    StableDirs = {Sysroot, ScanInstance.getHeaderSearchOpts ().ResourceDir };
567+   return  StableDirs;
568+ }
445569
570+ std::optional<PrebuiltModulesAttrsMap>
571+ computePrebuiltModulesASTMap (CompilerInstance &ScanInstance,
572+                              llvm::SmallVector<StringRef> &StableDirs) {
446573  //  Store a mapping of prebuilt module files and their properties like header
447574  //  search options. This will prevent the implicit build to create duplicate
448575  //  modules and will force reuse of the existing prebuilt module files
@@ -454,12 +581,14 @@ bool DependencyScanningAction::runInvocation(
454581            ScanInstance.getPreprocessorOpts ().ImplicitPCHInclude , ScanInstance,
455582            ScanInstance.getHeaderSearchOpts ().PrebuiltModuleFiles ,
456583            PrebuiltModulesASTMap, ScanInstance.getDiagnostics (), StableDirs))
457-       return  false ;
584+       return  {} ;
458585
459-   //  Create the dependency collector that will collect the produced
460-   //  dependencies.
461-   // 
462-   //  This also moves the existing dependency output options from the
586+   return  PrebuiltModulesASTMap;
587+ }
588+ 
589+ std::unique_ptr<DependencyOutputOptions>
590+ takeDependencyOutputOptionsFrom (CompilerInstance &ScanInstance) {
591+   //  This function moves the existing dependency output options from the
463592  //  invocation to the collector. The options in the invocation are reset,
464593  //  which ensures that the compiler won't create new dependency collectors,
465594  //  and thus won't write out the extra '.d' files to disk.
@@ -472,35 +601,85 @@ bool DependencyScanningAction::runInvocation(
472601                                     ScanInstance.getFrontendOpts ().Inputs )};
473602  Opts->IncludeSystemHeaders  = true ;
474603
604+   return  Opts;
605+ }
606+ 
607+ std::shared_ptr<ModuleDepCollector> initializeScanInstanceDependencyCollector (
608+     CompilerInstance &ScanInstance,
609+     std::unique_ptr<DependencyOutputOptions> DepOutputOpts,
610+     StringRef WorkingDirectory, DependencyConsumer &Consumer,
611+     DependencyScanningService &Service, CompilerInvocation &Inv,
612+     DependencyActionController &Controller,
613+     PrebuiltModulesAttrsMap PrebuiltModulesASTMap,
614+     llvm::SmallVector<StringRef> &StableDirs) {
615+   std::shared_ptr<ModuleDepCollector> MDC;
475616  switch  (Service.getFormat ()) {
476617  case  ScanningOutputFormat::Make:
477618    ScanInstance.addDependencyCollector (
478619        std::make_shared<DependencyConsumerForwarder>(
479-             std::move (Opts ), WorkingDirectory, Consumer));
620+             std::move (DepOutputOpts ), WorkingDirectory, Consumer));
480621    break ;
481622  case  ScanningOutputFormat::P1689:
482623  case  ScanningOutputFormat::Full:
483624    MDC = std::make_shared<ModuleDepCollector>(
484-         Service, std::move (Opts ), ScanInstance, Consumer, Controller,
485-         OriginalInvocation , std::move (PrebuiltModulesASTMap), StableDirs);
625+         Service, std::move (DepOutputOpts ), ScanInstance, Consumer, Controller,
626+         Inv , std::move (PrebuiltModulesASTMap), StableDirs);
486627    ScanInstance.addDependencyCollector (MDC);
487628    break ;
488629  }
489630
490-   //  Consider different header search and diagnostic options to create
491-   //  different modules. This avoids the unsound aliasing of module PCMs.
492-   // 
493-   //  TODO: Implement diagnostic bucketing to reduce the impact of strict
494-   //  context hashing.
495-   ScanInstance.getHeaderSearchOpts ().ModulesStrictContextHash  = true ;
496-   ScanInstance.getHeaderSearchOpts ().ModulesSerializeOnlyPreprocessor  = true ;
497-   ScanInstance.getHeaderSearchOpts ().ModulesSkipDiagnosticOptions  = true ;
498-   ScanInstance.getHeaderSearchOpts ().ModulesSkipHeaderSearchPaths  = true ;
499-   ScanInstance.getHeaderSearchOpts ().ModulesSkipPragmaDiagnosticMappings  = true ;
500-   ScanInstance.getHeaderSearchOpts ().ModulesForceValidateUserHeaders  = false ;
631+   return  MDC;
632+ }
633+ } //  namespace clang::tooling::dependencies
501634
502-   //  Avoid some checks and module map parsing when loading PCM files.
503-   ScanInstance.getPreprocessorOpts ().ModulesCheckRelocated  = false ;
635+ bool  DependencyScanningAction::runInvocation (
636+     std::unique_ptr<CompilerInvocation> Invocation,
637+     IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
638+     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
639+     DiagnosticConsumer *DiagConsumer) {
640+   //  Making sure that we canonicalize the defines before we create the deep
641+   //  copy to avoid unnecessary variants in the scanner and in the resulting
642+   //  explicit command lines.
643+   if  (any (Service.getOptimizeArgs () & ScanningOptimizations::Macros))
644+     canonicalizeDefines (Invocation->getPreprocessorOpts ());
645+ 
646+   //  Make a deep copy of the original Clang invocation.
647+   CompilerInvocation OriginalInvocation (*Invocation);
648+ 
649+   if  (Scanned) {
650+     //  Scanning runs once for the first -cc1 invocation in a chain of driver
651+     //  jobs. For any dependent jobs, reuse the scanning result and just
652+     //  update the LastCC1Arguments to correspond to the new invocation.
653+     //  FIXME: to support multi-arch builds, each arch requires a separate scan
654+     setLastCC1Arguments (std::move (OriginalInvocation));
655+     return  true ;
656+   }
657+ 
658+   Scanned = true ;
659+ 
660+   //  Create a compiler instance to handle the actual work.
661+   auto  ModCache = makeInProcessModuleCache (Service.getModuleCacheEntries ());
662+   ScanInstanceStorage.emplace (std::move (Invocation), std::move (PCHContainerOps),
663+                               ModCache.get ());
664+   CompilerInstance &ScanInstance = *ScanInstanceStorage;
665+ 
666+   assert (!DiagConsumerFinished && " attempt to reuse finished consumer" 
667+   if  (!initializeScanCompilerInstance (ScanInstance, FS, DiagConsumer, Service,
668+                                       DepFS))
669+     return  false ;
670+ 
671+   llvm::SmallVector<StringRef> StableDirs = getInitialStableDirs (ScanInstance);
672+   auto  MaybePrebuiltModulesASTMap =
673+       computePrebuiltModulesASTMap (ScanInstance, StableDirs);
674+   if  (!MaybePrebuiltModulesASTMap)
675+     return  false ;
676+ 
677+   auto  DepOutputOpts = takeDependencyOutputOptionsFrom (ScanInstance);
678+ 
679+   MDC = initializeScanInstanceDependencyCollector (
680+       ScanInstance, std::move (DepOutputOpts), WorkingDirectory, Consumer,
681+       Service, OriginalInvocation, Controller, *MaybePrebuiltModulesASTMap,
682+       StableDirs);
504683
505684  std::unique_ptr<FrontendAction> Action;
506685
0 commit comments