@@ -90,63 +90,140 @@ 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+ auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace (Filename);
120+ PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first ->second ;
121+ if (PrebuiltMapEntry.second )
122+ PrebuiltModule.setInStableDir (!StableDirs.empty ());
123+
124+ if (auto It = PrebuiltModulesASTMap.find (CurrentFile);
125+ It != PrebuiltModulesASTMap.end () && CurrentFile != Filename)
126+ PrebuiltModule.addDependent (It->getKey ());
127+ }
128+
129+ // / For each input file discovered, check whether it's external path is in a
130+ // / stable directory. Traversal is stopped if the current module is not
131+ // / considered stable.
132+ bool visitInputFile (StringRef FilenameAsRequested, StringRef Filename,
133+ bool isSystem, bool isOverridden,
134+ bool isExplicitModule) override {
135+ if (StableDirs.empty ())
136+ return false ;
137+ auto PrebuiltEntryIt = PrebuiltModulesASTMap.find (CurrentFile);
138+ if ((PrebuiltEntryIt == PrebuiltModulesASTMap.end ()) ||
139+ (!PrebuiltEntryIt->second .isInStableDir ()))
140+ return false ;
141+
142+ PrebuiltEntryIt->second .setInStableDir (
143+ isPathInStableDir (StableDirs, Filename));
144+ return PrebuiltEntryIt->second .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+ auto PrebuiltEntryIt = PrebuiltModulesASTMap.find (CurrentFile);
153+ if ((PrebuiltEntryIt != PrebuiltModulesASTMap.end ()) &&
154+ !PrebuiltEntryIt->second .isInStableDir ())
155+ PrebuiltEntryIt->second .updateDependentsNotInStableDirs (
156+ PrebuiltModulesASTMap);
116157 CurrentFile = Filename;
117158 }
118159
160+ // / Check the header search options for a given module when considering
161+ // / if the module comes from stable directories.
162+ bool ReadHeaderSearchOptions (const HeaderSearchOptions &HSOpts,
163+ StringRef ModuleFilename,
164+ StringRef SpecificModuleCachePath,
165+ bool Complain) override {
166+
167+ auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace (CurrentFile);
168+ PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first ->second ;
169+ if (PrebuiltMapEntry.second )
170+ PrebuiltModule.setInStableDir (!StableDirs.empty ());
171+
172+ if (PrebuiltModule.isInStableDir ())
173+ PrebuiltModule.setInStableDir (areOptionsInStableDir (StableDirs, HSOpts));
174+
175+ return false ;
176+ }
177+
178+ // / Accumulate vfsoverlays used to build these prebuilt modules.
119179 bool ReadHeaderSearchPaths (const HeaderSearchOptions &HSOpts,
120180 bool Complain) override {
121- std::vector<std::string> VFSOverlayFiles = HSOpts.VFSOverlayFiles ;
122- PrebuiltModuleVFSMap.try_emplace (CurrentFile, llvm::from_range,
123- VFSOverlayFiles);
181+
182+ auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace (CurrentFile);
183+ PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first ->second ;
184+ if (PrebuiltMapEntry.second )
185+ PrebuiltModule.setInStableDir (!StableDirs.empty ());
186+
187+ PrebuiltModule.setVFS (
188+ llvm::StringSet<>(llvm::from_range, HSOpts.VFSOverlayFiles ));
189+
124190 return checkHeaderSearchPaths (
125191 HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr , ExistingLangOpts);
126192 }
127193
128194private:
129195 PrebuiltModuleFilesT &PrebuiltModuleFiles;
130196 llvm::SmallVector<std::string> &NewModuleFiles;
131- PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap ;
197+ PrebuiltModulesAttrsMap &PrebuiltModulesASTMap ;
132198 const HeaderSearchOptions &ExistingHSOpts;
133199 const LangOptions &ExistingLangOpts;
134200 DiagnosticsEngine &Diags;
135201 std::string CurrentFile;
202+ const llvm::SmallVector<StringRef> &StableDirs;
136203};
137204
138205// / Visit the given prebuilt module and collect all of the modules it
139206// / transitively imports and contributing input files.
140207static bool visitPrebuiltModule (StringRef PrebuiltModuleFilename,
141208 CompilerInstance &CI,
142209 PrebuiltModuleFilesT &ModuleFiles,
143- PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap ,
210+ PrebuiltModulesAttrsMap &PrebuiltModulesASTMap ,
144211 DiagnosticsEngine &Diags) {
212+
213+ // Gather the set of stable directories to use as transitive dependencies are
214+ // discovered.
215+ llvm::SmallVector<StringRef> StableDirs;
216+ std::string SysrootToUse (CI.getHeaderSearchOpts ().Sysroot );
217+ if (!SysrootToUse.empty () &&
218+ (llvm::sys::path::root_directory (SysrootToUse) != SysrootToUse))
219+ StableDirs = {SysrootToUse, CI.getHeaderSearchOpts ().ResourceDir };
220+
145221 // List of module files to be processed.
146222 llvm::SmallVector<std::string> Worklist;
147- PrebuiltModuleListener Listener (ModuleFiles, Worklist, PrebuiltModuleVFSMap,
223+
224+ PrebuiltModuleListener Listener (ModuleFiles, Worklist, PrebuiltModulesASTMap,
148225 CI.getHeaderSearchOpts (), CI.getLangOpts (),
149- Diags);
226+ Diags, StableDirs );
150227
151228 Listener.visitModuleFile (PrebuiltModuleFilename,
152229 serialization::MK_ExplicitModule);
@@ -371,16 +448,18 @@ class DependencyScanningAction : public tooling::ToolAction {
371448 auto *FileMgr = ScanInstance.createFileManager (FS);
372449 ScanInstance.createSourceManager (*FileMgr);
373450
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;
451+ // Store a mapping of prebuilt module files and their properties like header
452+ // search options. This will prevent the implicit build to create duplicate
453+ // modules and will force reuse of the existing prebuilt module files
454+ // instead.
455+ PrebuiltModulesAttrsMap PrebuiltModulesASTMap;
456+
378457 if (!ScanInstance.getPreprocessorOpts ().ImplicitPCHInclude .empty ())
379458 if (visitPrebuiltModule (
380459 ScanInstance.getPreprocessorOpts ().ImplicitPCHInclude ,
381460 ScanInstance,
382461 ScanInstance.getHeaderSearchOpts ().PrebuiltModuleFiles ,
383- PrebuiltModuleVFSMap , ScanInstance.getDiagnostics ()))
462+ PrebuiltModulesASTMap , ScanInstance.getDiagnostics ()))
384463 return false ;
385464
386465 // Create the dependency collector that will collect the produced
@@ -410,7 +489,7 @@ class DependencyScanningAction : public tooling::ToolAction {
410489 case ScanningOutputFormat::Full:
411490 MDC = std::make_shared<ModuleDepCollector>(
412491 Service, std::move (Opts), ScanInstance, Consumer, Controller,
413- OriginalInvocation, std::move (PrebuiltModuleVFSMap ));
492+ OriginalInvocation, std::move (PrebuiltModulesASTMap ));
414493 ScanInstance.addDependencyCollector (MDC);
415494 break ;
416495 }
0 commit comments