2424#include " clang/Tooling/DependencyScanning/DependencyScanningService.h"
2525#include " clang/Tooling/DependencyScanning/ModuleDepCollector.h"
2626#include " clang/Tooling/Tooling.h"
27+ #include " llvm/ADT/ScopeExit.h"
2728#include " llvm/Support/Allocator.h"
2829#include " llvm/Support/Error.h"
2930#include " llvm/TargetParser/Host.h"
@@ -67,7 +68,7 @@ static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
6768 if (LangOpts.Modules ) {
6869 if (HSOpts.VFSOverlayFiles != ExistingHSOpts.VFSOverlayFiles ) {
6970 if (Diags) {
70- Diags->Report (diag::err_pch_vfsoverlay_mismatch );
71+ Diags->Report (diag::warn_pch_vfsoverlay_mismatch );
7172 auto VFSNote = [&](int Type, ArrayRef<std::string> VFSOverlays) {
7273 if (VFSOverlays.empty ()) {
7374 Diags->Report (diag::note_pch_vfsoverlay_empty) << Type;
@@ -79,7 +80,6 @@ static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
7980 VFSNote (0 , HSOpts.VFSOverlayFiles );
8081 VFSNote (1 , ExistingHSOpts.VFSOverlayFiles );
8182 }
82- return true ;
8383 }
8484 }
8585 return false ;
@@ -93,10 +93,12 @@ class PrebuiltModuleListener : public ASTReaderListener {
9393public:
9494 PrebuiltModuleListener (PrebuiltModuleFilesT &PrebuiltModuleFiles,
9595 llvm::SmallVector<std::string> &NewModuleFiles,
96+ PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
9697 const HeaderSearchOptions &HSOpts,
9798 const LangOptions &LangOpts, DiagnosticsEngine &Diags)
9899 : PrebuiltModuleFiles(PrebuiltModuleFiles),
99- NewModuleFiles (NewModuleFiles), ExistingHSOpts(HSOpts),
100+ NewModuleFiles (NewModuleFiles),
101+ PrebuiltModuleVFSMap(PrebuiltModuleVFSMap), ExistingHSOpts(HSOpts),
100102 ExistingLangOpts(LangOpts), Diags(Diags) {}
101103
102104 bool needsImportVisitation () const override { return true ; }
@@ -106,31 +108,45 @@ class PrebuiltModuleListener : public ASTReaderListener {
106108 NewModuleFiles.push_back (Filename.str ());
107109 }
108110
111+ void visitModuleFile (StringRef Filename,
112+ serialization::ModuleKind Kind) override {
113+ CurrentFile = Filename;
114+ }
115+
109116 bool ReadHeaderSearchPaths (const HeaderSearchOptions &HSOpts,
110117 bool Complain) override {
118+ std::vector<std::string> VFSOverlayFiles = HSOpts.VFSOverlayFiles ;
119+ PrebuiltModuleVFSMap.insert (
120+ {CurrentFile, llvm::StringSet<>(VFSOverlayFiles)});
111121 return checkHeaderSearchPaths (
112122 HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr , ExistingLangOpts);
113123 }
114124
115125private:
116126 PrebuiltModuleFilesT &PrebuiltModuleFiles;
117127 llvm::SmallVector<std::string> &NewModuleFiles;
128+ PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap;
118129 const HeaderSearchOptions &ExistingHSOpts;
119130 const LangOptions &ExistingLangOpts;
120131 DiagnosticsEngine &Diags;
132+ std::string CurrentFile;
121133};
122134
123135// / Visit the given prebuilt module and collect all of the modules it
124136// / transitively imports and contributing input files.
125137static bool visitPrebuiltModule (StringRef PrebuiltModuleFilename,
126138 CompilerInstance &CI,
127139 PrebuiltModuleFilesT &ModuleFiles,
140+ PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
128141 DiagnosticsEngine &Diags) {
129142 // List of module files to be processed.
130143 llvm::SmallVector<std::string> Worklist;
131- PrebuiltModuleListener Listener (
132- ModuleFiles, Worklist, CI.getHeaderSearchOpts (), CI.getLangOpts (), Diags);
144+ PrebuiltModuleListener Listener (ModuleFiles, Worklist, PrebuiltModuleVFSMap,
145+ CI.getHeaderSearchOpts (), CI.getLangOpts (),
146+ Diags);
133147
148+ Listener.visitModuleFile (PrebuiltModuleFilename,
149+ serialization::MK_ExplicitModule);
134150 if (ASTReader::readASTFileControlBlock (
135151 PrebuiltModuleFilename, CI.getFileManager (), CI.getModuleCache (),
136152 CI.getPCHContainerReader (),
@@ -139,6 +155,7 @@ static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename,
139155 return true ;
140156
141157 while (!Worklist.empty ()) {
158+ Listener.visitModuleFile (Worklist.back (), serialization::MK_ExplicitModule);
142159 if (ASTReader::readASTFileControlBlock (
143160 Worklist.pop_back_val (), CI.getFileManager (), CI.getModuleCache (),
144161 CI.getPCHContainerReader (),
@@ -175,8 +192,19 @@ static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) {
175192 DiagOpts.ShowCarets = false ;
176193 // Don't write out diagnostic file.
177194 DiagOpts.DiagnosticSerializationFile .clear ();
178- // Don't emit warnings as errors (and all other warnings too).
179- DiagOpts.IgnoreWarnings = true ;
195+ // Don't emit warnings except for scanning specific warnings.
196+ // TODO: It would be useful to add a more principled way to ignore all
197+ // warnings that come from source code. The issue is that we need to
198+ // ignore warnings that could be surpressed by
199+ // `#pragma clang diagnostic`, while still allowing some scanning
200+ // warnings for things we're not ready to turn into errors yet.
201+ // See `test/ClangScanDeps/diagnostic-pragmas.c` for an example.
202+ llvm::erase_if (DiagOpts.Warnings , [](StringRef Warning) {
203+ return llvm::StringSwitch<bool >(Warning)
204+ .Cases (" pch-vfs-diff" , " error=pch-vfs-diff" , false )
205+ .StartsWith (" no-error=" , false )
206+ .Default (true );
207+ });
180208}
181209
182210// Clang implements -D and -U by splatting text into a predefines buffer. This
@@ -300,14 +328,19 @@ class DependencyScanningAction : public tooling::ToolAction {
300328 if (!ScanInstance.hasDiagnostics ())
301329 return false ;
302330
331+ // Some DiagnosticConsumers require that finish() is called.
332+ auto DiagConsumerFinisher =
333+ llvm::make_scope_exit ([DiagConsumer]() { DiagConsumer->finish (); });
334+
303335 ScanInstance.getPreprocessorOpts ().AllowPCHWithDifferentModulesCachePath =
304336 true ;
305337
306338 ScanInstance.getFrontendOpts ().GenerateGlobalModuleIndex = false ;
307339 ScanInstance.getFrontendOpts ().UseGlobalModuleIndex = false ;
308340 ScanInstance.getFrontendOpts ().ModulesShareFileManager = false ;
309341 ScanInstance.getHeaderSearchOpts ().ModuleFormat = " raw" ;
310- ScanInstance.getHeaderSearchOpts ().ModulesIncludeVFSUsage = true ;
342+ ScanInstance.getHeaderSearchOpts ().ModulesIncludeVFSUsage =
343+ any (OptimizeArgs & ScanningOptimizations::VFS);
311344
312345 ScanInstance.setFileManager (FileMgr);
313346 // Support for virtual file system overlays.
@@ -320,12 +353,13 @@ class DependencyScanningAction : public tooling::ToolAction {
320353 // Store the list of prebuilt module files into header search options. This
321354 // will prevent the implicit build to create duplicate modules and will
322355 // force reuse of the existing prebuilt module files instead.
356+ PrebuiltModuleVFSMapT PrebuiltModuleVFSMap;
323357 if (!ScanInstance.getPreprocessorOpts ().ImplicitPCHInclude .empty ())
324358 if (visitPrebuiltModule (
325359 ScanInstance.getPreprocessorOpts ().ImplicitPCHInclude ,
326360 ScanInstance,
327361 ScanInstance.getHeaderSearchOpts ().PrebuiltModuleFiles ,
328- ScanInstance.getDiagnostics ()))
362+ PrebuiltModuleVFSMap, ScanInstance.getDiagnostics ()))
329363 return false ;
330364
331365 // Use the dependency scanning optimized file system if requested to do so.
@@ -369,8 +403,8 @@ class DependencyScanningAction : public tooling::ToolAction {
369403 case ScanningOutputFormat::Full:
370404 MDC = std::make_shared<ModuleDepCollector>(
371405 std::move (Opts), ScanInstance, Consumer, Controller,
372- OriginalInvocation, OptimizeArgs, EagerLoadModules ,
373- Format == ScanningOutputFormat::P1689);
406+ OriginalInvocation, std::move (PrebuiltModuleVFSMap), OptimizeArgs ,
407+ EagerLoadModules, Format == ScanningOutputFormat::P1689);
374408 ScanInstance.addDependencyCollector (MDC);
375409 break ;
376410 }
@@ -399,6 +433,8 @@ class DependencyScanningAction : public tooling::ToolAction {
399433 if (ScanInstance.getDiagnostics ().hasErrorOccurred ())
400434 return false ;
401435
436+ // Each action is responsible for calling finish.
437+ DiagConsumerFinisher.release ();
402438 const bool Result = ScanInstance.ExecuteAction (*Action);
403439
404440 if (Result)
0 commit comments