24
24
#include " clang/Tooling/DependencyScanning/DependencyScanningService.h"
25
25
#include " clang/Tooling/DependencyScanning/ModuleDepCollector.h"
26
26
#include " clang/Tooling/Tooling.h"
27
+ #include " llvm/ADT/ScopeExit.h"
27
28
#include " llvm/Support/Allocator.h"
28
29
#include " llvm/Support/Error.h"
29
30
#include " llvm/TargetParser/Host.h"
@@ -67,7 +68,7 @@ static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
67
68
if (LangOpts.Modules ) {
68
69
if (HSOpts.VFSOverlayFiles != ExistingHSOpts.VFSOverlayFiles ) {
69
70
if (Diags) {
70
- Diags->Report (diag::err_pch_vfsoverlay_mismatch );
71
+ Diags->Report (diag::warn_pch_vfsoverlay_mismatch );
71
72
auto VFSNote = [&](int Type, ArrayRef<std::string> VFSOverlays) {
72
73
if (VFSOverlays.empty ()) {
73
74
Diags->Report (diag::note_pch_vfsoverlay_empty) << Type;
@@ -79,7 +80,6 @@ static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
79
80
VFSNote (0 , HSOpts.VFSOverlayFiles );
80
81
VFSNote (1 , ExistingHSOpts.VFSOverlayFiles );
81
82
}
82
- return true ;
83
83
}
84
84
}
85
85
return false ;
@@ -93,10 +93,12 @@ class PrebuiltModuleListener : public ASTReaderListener {
93
93
public:
94
94
PrebuiltModuleListener (PrebuiltModuleFilesT &PrebuiltModuleFiles,
95
95
llvm::SmallVector<std::string> &NewModuleFiles,
96
+ PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
96
97
const HeaderSearchOptions &HSOpts,
97
98
const LangOptions &LangOpts, DiagnosticsEngine &Diags)
98
99
: PrebuiltModuleFiles(PrebuiltModuleFiles),
99
- NewModuleFiles (NewModuleFiles), ExistingHSOpts(HSOpts),
100
+ NewModuleFiles (NewModuleFiles),
101
+ PrebuiltModuleVFSMap(PrebuiltModuleVFSMap), ExistingHSOpts(HSOpts),
100
102
ExistingLangOpts(LangOpts), Diags(Diags) {}
101
103
102
104
bool needsImportVisitation () const override { return true ; }
@@ -106,31 +108,45 @@ class PrebuiltModuleListener : public ASTReaderListener {
106
108
NewModuleFiles.push_back (Filename.str ());
107
109
}
108
110
111
+ void visitModuleFile (StringRef Filename,
112
+ serialization::ModuleKind Kind) override {
113
+ CurrentFile = Filename;
114
+ }
115
+
109
116
bool ReadHeaderSearchPaths (const HeaderSearchOptions &HSOpts,
110
117
bool Complain) override {
118
+ std::vector<std::string> VFSOverlayFiles = HSOpts.VFSOverlayFiles ;
119
+ PrebuiltModuleVFSMap.insert (
120
+ {CurrentFile, llvm::StringSet<>(VFSOverlayFiles)});
111
121
return checkHeaderSearchPaths (
112
122
HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr , ExistingLangOpts);
113
123
}
114
124
115
125
private:
116
126
PrebuiltModuleFilesT &PrebuiltModuleFiles;
117
127
llvm::SmallVector<std::string> &NewModuleFiles;
128
+ PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap;
118
129
const HeaderSearchOptions &ExistingHSOpts;
119
130
const LangOptions &ExistingLangOpts;
120
131
DiagnosticsEngine &Diags;
132
+ std::string CurrentFile;
121
133
};
122
134
123
135
// / Visit the given prebuilt module and collect all of the modules it
124
136
// / transitively imports and contributing input files.
125
137
static bool visitPrebuiltModule (StringRef PrebuiltModuleFilename,
126
138
CompilerInstance &CI,
127
139
PrebuiltModuleFilesT &ModuleFiles,
140
+ PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
128
141
DiagnosticsEngine &Diags) {
129
142
// List of module files to be processed.
130
143
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);
133
147
148
+ Listener.visitModuleFile (PrebuiltModuleFilename,
149
+ serialization::MK_ExplicitModule);
134
150
if (ASTReader::readASTFileControlBlock (
135
151
PrebuiltModuleFilename, CI.getFileManager (), CI.getModuleCache (),
136
152
CI.getPCHContainerReader (),
@@ -139,6 +155,7 @@ static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename,
139
155
return true ;
140
156
141
157
while (!Worklist.empty ()) {
158
+ Listener.visitModuleFile (Worklist.back (), serialization::MK_ExplicitModule);
142
159
if (ASTReader::readASTFileControlBlock (
143
160
Worklist.pop_back_val (), CI.getFileManager (), CI.getModuleCache (),
144
161
CI.getPCHContainerReader (),
@@ -175,8 +192,19 @@ static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) {
175
192
DiagOpts.ShowCarets = false ;
176
193
// Don't write out diagnostic file.
177
194
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
+ });
180
208
}
181
209
182
210
// Clang implements -D and -U by splatting text into a predefines buffer. This
@@ -300,14 +328,19 @@ class DependencyScanningAction : public tooling::ToolAction {
300
328
if (!ScanInstance.hasDiagnostics ())
301
329
return false ;
302
330
331
+ // Some DiagnosticConsumers require that finish() is called.
332
+ auto DiagConsumerFinisher =
333
+ llvm::make_scope_exit ([DiagConsumer]() { DiagConsumer->finish (); });
334
+
303
335
ScanInstance.getPreprocessorOpts ().AllowPCHWithDifferentModulesCachePath =
304
336
true ;
305
337
306
338
ScanInstance.getFrontendOpts ().GenerateGlobalModuleIndex = false ;
307
339
ScanInstance.getFrontendOpts ().UseGlobalModuleIndex = false ;
308
340
ScanInstance.getFrontendOpts ().ModulesShareFileManager = false ;
309
341
ScanInstance.getHeaderSearchOpts ().ModuleFormat = " raw" ;
310
- ScanInstance.getHeaderSearchOpts ().ModulesIncludeVFSUsage = true ;
342
+ ScanInstance.getHeaderSearchOpts ().ModulesIncludeVFSUsage =
343
+ any (OptimizeArgs & ScanningOptimizations::VFS);
311
344
312
345
ScanInstance.setFileManager (FileMgr);
313
346
// Support for virtual file system overlays.
@@ -320,12 +353,13 @@ class DependencyScanningAction : public tooling::ToolAction {
320
353
// Store the list of prebuilt module files into header search options. This
321
354
// will prevent the implicit build to create duplicate modules and will
322
355
// force reuse of the existing prebuilt module files instead.
356
+ PrebuiltModuleVFSMapT PrebuiltModuleVFSMap;
323
357
if (!ScanInstance.getPreprocessorOpts ().ImplicitPCHInclude .empty ())
324
358
if (visitPrebuiltModule (
325
359
ScanInstance.getPreprocessorOpts ().ImplicitPCHInclude ,
326
360
ScanInstance,
327
361
ScanInstance.getHeaderSearchOpts ().PrebuiltModuleFiles ,
328
- ScanInstance.getDiagnostics ()))
362
+ PrebuiltModuleVFSMap, ScanInstance.getDiagnostics ()))
329
363
return false ;
330
364
331
365
// Use the dependency scanning optimized file system if requested to do so.
@@ -369,8 +403,8 @@ class DependencyScanningAction : public tooling::ToolAction {
369
403
case ScanningOutputFormat::Full:
370
404
MDC = std::make_shared<ModuleDepCollector>(
371
405
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);
374
408
ScanInstance.addDependencyCollector (MDC);
375
409
break ;
376
410
}
@@ -399,6 +433,8 @@ class DependencyScanningAction : public tooling::ToolAction {
399
433
if (ScanInstance.getDiagnostics ().hasErrorOccurred ())
400
434
return false ;
401
435
436
+ // Each action is responsible for calling finish.
437
+ DiagConsumerFinisher.release ();
402
438
const bool Result = ScanInstance.ExecuteAction (*Action);
403
439
404
440
if (Result)
0 commit comments