@@ -90,63 +90,135 @@ static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
9090
9191using PrebuiltModuleFilesT = decltype (HeaderSearchOptions::PrebuiltModuleFiles);
9292
93- // / A listener that collects the imported modules and optionally the input
94- // / files.
93+ // / A listener that collects the imported modules and the input
94+ // / files. While visiting, collect vfsoverlays and file inputs that determine
95+ // / whether prebuilt modules fully resolve in stable directories.
9596class PrebuiltModuleListener : public ASTReaderListener {
9697public:
9798 PrebuiltModuleListener (PrebuiltModuleFilesT &PrebuiltModuleFiles,
9899 llvm::SmallVector<std::string> &NewModuleFiles,
99- PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap ,
100+ PrebuiltModulesAttrsMap &PrebuiltModulesASTMap ,
100101 const HeaderSearchOptions &HSOpts,
101- const LangOptions &LangOpts, DiagnosticsEngine &Diags)
102+ const LangOptions &LangOpts, DiagnosticsEngine &Diags,
103+ const llvm::SmallVector<StringRef> &StableDirs)
102104 : PrebuiltModuleFiles(PrebuiltModuleFiles),
103105 NewModuleFiles (NewModuleFiles),
104- PrebuiltModuleVFSMap(PrebuiltModuleVFSMap ), ExistingHSOpts(HSOpts),
105- ExistingLangOpts(LangOpts), Diags(Diags) {}
106+ PrebuiltModulesASTMap(PrebuiltModulesASTMap ), ExistingHSOpts(HSOpts),
107+ ExistingLangOpts(LangOpts), Diags(Diags), StableDirs(StableDirs) {}
106108
107109 bool needsImportVisitation () const override { return true ; }
110+ bool needsInputFileVisitation () override { return true ; }
111+ bool needsSystemInputFileVisitation () override { return true ; }
108112
113+ // / Accumulate the modules are transitively depended on by the initial
114+ // / prebuilt module.
109115 void visitImport (StringRef ModuleName, StringRef Filename) override {
110116 if (PrebuiltModuleFiles.insert ({ModuleName.str (), Filename.str ()}).second )
111117 NewModuleFiles.push_back (Filename.str ());
118+
119+ if (PrebuiltModulesASTMap.try_emplace (Filename).second )
120+ PrebuiltModulesASTMap[Filename].setInStableDir (!StableDirs.empty ());
121+
122+ if (auto It = PrebuiltModulesASTMap.find (CurrentFile);
123+ It != PrebuiltModulesASTMap.end () && CurrentFile != Filename)
124+ PrebuiltModulesASTMap[Filename].addDependent (It->getKey ());
125+ }
126+
127+ // / For each input file discovered, check whether it's external path is in a
128+ // / stable directory. Traversal is stopped if the current module is not
129+ // / considered stable.
130+ bool visitInputFile (StringRef FilenameAsRequested, StringRef ExternalFilename,
131+ bool isSystem, bool isOverridden,
132+ bool isExplicitModule) override {
133+ if (StableDirs.empty ())
134+ return false ;
135+ if (!PrebuiltModulesASTMap.contains (CurrentFile) ||
136+ !PrebuiltModulesASTMap[CurrentFile].isInStableDir ())
137+ return false ;
138+
139+ const StringRef FileToUse =
140+ ExternalFilename.empty () ? FilenameAsRequested : ExternalFilename;
141+
142+ PrebuiltModulesASTMap[CurrentFile].setInStableDir (
143+ isPathInStableDir (StableDirs, FileToUse));
144+ return PrebuiltModulesASTMap[CurrentFile].isInStableDir ();
112145 }
113146
147+ // / Update which module that is being actively traversed.
114148 void visitModuleFile (StringRef Filename,
115149 serialization::ModuleKind Kind) override {
150+ // If the CurrentFile is not
151+ // considered stable, update any of it's transitive dependents.
152+ if (PrebuiltModulesASTMap.contains (CurrentFile) &&
153+ !PrebuiltModulesASTMap[CurrentFile].isInStableDir ())
154+ PrebuiltModulesASTMap[CurrentFile].updateDependentsNotInStableDirs (
155+ PrebuiltModulesASTMap);
116156 CurrentFile = Filename;
117157 }
118158
159+ // / Check the header search options for a given module when considering
160+ // / if the module comes from stable directories.
161+ bool ReadHeaderSearchOptions (const HeaderSearchOptions &HSOpts,
162+ StringRef ModuleFilename,
163+ StringRef SpecificModuleCachePath,
164+ bool Complain) override {
165+ if (PrebuiltModulesASTMap.try_emplace (CurrentFile).second )
166+ PrebuiltModulesASTMap[CurrentFile].setInStableDir (!StableDirs.empty ());
167+
168+ if (PrebuiltModulesASTMap[CurrentFile].isInStableDir ())
169+ PrebuiltModulesASTMap[CurrentFile].setInStableDir (
170+ areOptionsInStableDir (StableDirs, HSOpts));
171+
172+ return false ;
173+ }
174+
175+ // / Accumulate vfsoverlays used to build these prebuilt modules.
119176 bool ReadHeaderSearchPaths (const HeaderSearchOptions &HSOpts,
120177 bool Complain) override {
121- std::vector<std::string> VFSOverlayFiles = HSOpts.VFSOverlayFiles ;
122- PrebuiltModuleVFSMap.try_emplace (CurrentFile, llvm::from_range,
123- VFSOverlayFiles);
178+
179+ if (PrebuiltModulesASTMap.try_emplace (CurrentFile).second )
180+ PrebuiltModulesASTMap[CurrentFile].setInStableDir (!StableDirs.empty ());
181+
182+ PrebuiltModulesASTMap[CurrentFile].setVFS (
183+ llvm::StringSet<>(llvm::from_range, HSOpts.VFSOverlayFiles ));
184+
124185 return checkHeaderSearchPaths (
125186 HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr , ExistingLangOpts);
126187 }
127188
128189private:
129190 PrebuiltModuleFilesT &PrebuiltModuleFiles;
130191 llvm::SmallVector<std::string> &NewModuleFiles;
131- PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap ;
192+ PrebuiltModulesAttrsMap &PrebuiltModulesASTMap ;
132193 const HeaderSearchOptions &ExistingHSOpts;
133194 const LangOptions &ExistingLangOpts;
134195 DiagnosticsEngine &Diags;
135196 std::string CurrentFile;
197+ const llvm::SmallVector<StringRef> &StableDirs;
136198};
137199
138200// / Visit the given prebuilt module and collect all of the modules it
139201// / transitively imports and contributing input files.
140202static bool visitPrebuiltModule (StringRef PrebuiltModuleFilename,
141203 CompilerInstance &CI,
142204 PrebuiltModuleFilesT &ModuleFiles,
143- PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap ,
205+ PrebuiltModulesAttrsMap &PrebuiltModulesASTMap ,
144206 DiagnosticsEngine &Diags) {
207+
208+ // Gather the set of stable directories to use as transitive dependencies are
209+ // discovered.
210+ llvm::SmallVector<StringRef> StableDirs;
211+ std::string SysrootToUse (CI.getHeaderSearchOpts ().Sysroot );
212+ if (!SysrootToUse.empty () &&
213+ (llvm::sys::path::root_directory (SysrootToUse) != SysrootToUse))
214+ StableDirs = {SysrootToUse, CI.getHeaderSearchOpts ().ResourceDir };
215+
145216 // List of module files to be processed.
146217 llvm::SmallVector<std::string> Worklist;
147- PrebuiltModuleListener Listener (ModuleFiles, Worklist, PrebuiltModuleVFSMap,
218+
219+ PrebuiltModuleListener Listener (ModuleFiles, Worklist, PrebuiltModulesASTMap,
148220 CI.getHeaderSearchOpts (), CI.getLangOpts (),
149- Diags);
221+ Diags, StableDirs );
150222
151223 Listener.visitModuleFile (PrebuiltModuleFilename,
152224 serialization::MK_ExplicitModule);
@@ -371,16 +443,18 @@ class DependencyScanningAction : public tooling::ToolAction {
371443 auto *FileMgr = ScanInstance.createFileManager (FS);
372444 ScanInstance.createSourceManager (*FileMgr);
373445
374- // Store the list of prebuilt module files into header search options. This
375- // will prevent the implicit build to create duplicate modules and will
376- // force reuse of the existing prebuilt module files instead.
377- PrebuiltModuleVFSMapT PrebuiltModuleVFSMap;
446+ // Store a mapping of prebuilt module files and their properties like header
447+ // search options. This will prevent the implicit build to create duplicate
448+ // modules and will force reuse of the existing prebuilt module files
449+ // instead.
450+ PrebuiltModulesAttrsMap PrebuiltModulesASTMap;
451+
378452 if (!ScanInstance.getPreprocessorOpts ().ImplicitPCHInclude .empty ())
379453 if (visitPrebuiltModule (
380454 ScanInstance.getPreprocessorOpts ().ImplicitPCHInclude ,
381455 ScanInstance,
382456 ScanInstance.getHeaderSearchOpts ().PrebuiltModuleFiles ,
383- PrebuiltModuleVFSMap , ScanInstance.getDiagnostics ()))
457+ PrebuiltModulesASTMap , ScanInstance.getDiagnostics ()))
384458 return false ;
385459
386460 // Create the dependency collector that will collect the produced
@@ -410,7 +484,7 @@ class DependencyScanningAction : public tooling::ToolAction {
410484 case ScanningOutputFormat::Full:
411485 MDC = std::make_shared<ModuleDepCollector>(
412486 Service, std::move (Opts), ScanInstance, Consumer, Controller,
413- OriginalInvocation, std::move (PrebuiltModuleVFSMap ));
487+ OriginalInvocation, std::move (PrebuiltModulesASTMap ));
414488 ScanInstance.addDependencyCollector (MDC);
415489 break ;
416490 }
0 commit comments