@@ -92,6 +92,87 @@ class FailedPrerequisiteModules : public PrerequisiteModules {
9292 }
9393};
9494
95+ struct ModuleFile {
96+ ModuleFile (StringRef ModuleName, PathRef ModuleFilePath)
97+ : ModuleName(ModuleName.str()), ModuleFilePath(ModuleFilePath.str()) {}
98+
99+ ModuleFile () = delete ;
100+
101+ ModuleFile (const ModuleFile &) = delete ;
102+ ModuleFile operator =(const ModuleFile &) = delete ;
103+
104+ // The move constructor is needed for llvm::SmallVector.
105+ ModuleFile (ModuleFile &&Other)
106+ : ModuleName(std::move(Other.ModuleName)),
107+ ModuleFilePath (std::move(Other.ModuleFilePath)) {
108+ Other.ModuleName .clear ();
109+ Other.ModuleFilePath .clear ();
110+ }
111+
112+ ModuleFile &operator =(ModuleFile &&Other) {
113+ if (this == &Other)
114+ return *this ;
115+
116+ this ->~ModuleFile ();
117+ new (this ) ModuleFile (std::move (Other));
118+ return *this ;
119+ }
120+
121+ ~ModuleFile () {
122+ if (!ModuleFilePath.empty ())
123+ llvm::sys::fs::remove (ModuleFilePath);
124+ }
125+
126+ std::string ModuleName;
127+ std::string ModuleFilePath;
128+ };
129+
130+ bool IsModuleFileUpToDate (
131+ PathRef ModuleFilePath,
132+ const PrerequisiteModules &RequisiteModules) {
133+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
134+ CompilerInstance::createDiagnostics (new DiagnosticOptions ());
135+
136+ auto HSOpts = std::make_shared<HeaderSearchOptions>();
137+ RequisiteModules.adjustHeaderSearchOptions (*HSOpts);
138+ HSOpts->ForceCheckCXX20ModulesInputFiles = true ;
139+ HSOpts->ValidateASTInputFilesContent = true ;
140+
141+ PCHContainerOperations PCHOperations;
142+ std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile (
143+ ModuleFilePath.str (), PCHOperations.getRawReader (), ASTUnit::LoadASTOnly,
144+ Diags, FileSystemOptions (), std::move (HSOpts));
145+
146+ if (!Unit)
147+ return false ;
148+
149+ auto Reader = Unit->getASTReader ();
150+ if (!Reader)
151+ return false ;
152+
153+ bool UpToDate = true ;
154+ Reader->getModuleManager ().visit ([&](serialization::ModuleFile &MF) -> bool {
155+ Reader->visitInputFiles (
156+ MF, /* IncludeSystem=*/ false , /* Complain=*/ false ,
157+ [&](const serialization::InputFile &IF, bool isSystem) {
158+ if (!IF.getFile () || IF.isOutOfDate ())
159+ UpToDate = false ;
160+ });
161+
162+ return !UpToDate;
163+ });
164+
165+ return UpToDate;
166+ }
167+
168+ bool IsModuleFilesUpToDate (
169+ llvm::SmallVector<PathRef> ModuleFilePaths,
170+ const PrerequisiteModules &RequisiteModules) {
171+ return llvm::all_of (ModuleFilePaths, [&RequisiteModules](auto ModuleFilePath) {
172+ return IsModuleFileUpToDate (ModuleFilePath, RequisiteModules);
173+ });
174+ }
175+
95176// StandalonePrerequisiteModules - stands for PrerequisiteModules for which all
96177// the required modules are built successfully. All the module files
97178// are owned by the StandalonePrerequisiteModules class.
@@ -135,29 +216,6 @@ class StandalonePrerequisiteModules : public PrerequisiteModules {
135216 }
136217
137218private:
138- struct ModuleFile {
139- ModuleFile (llvm::StringRef ModuleName, PathRef ModuleFilePath)
140- : ModuleName(ModuleName.str()), ModuleFilePath(ModuleFilePath.str()) {}
141-
142- ModuleFile (const ModuleFile &) = delete ;
143- ModuleFile operator =(const ModuleFile &) = delete ;
144-
145- // The move constructor is needed for llvm::SmallVector.
146- ModuleFile (ModuleFile &&Other)
147- : ModuleName(std::move(Other.ModuleName)),
148- ModuleFilePath (std::move(Other.ModuleFilePath)) {}
149-
150- ModuleFile &operator =(ModuleFile &&Other) = delete ;
151-
152- ~ModuleFile () {
153- if (!ModuleFilePath.empty ())
154- llvm::sys::fs::remove (ModuleFilePath);
155- }
156-
157- std::string ModuleName;
158- std::string ModuleFilePath;
159- };
160-
161219 llvm::SmallVector<ModuleFile, 8 > RequiredModules;
162220 // A helper class to speedup the query if a module is built.
163221 llvm::StringSet<> BuiltModuleNames;
@@ -286,50 +344,10 @@ bool StandalonePrerequisiteModules::canReuse(
286344 if (RequiredModules.empty ())
287345 return true ;
288346
289- CompilerInstance Clang;
290-
291- Clang.setInvocation (std::make_shared<CompilerInvocation>(CI));
292- IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
293- CompilerInstance::createDiagnostics (new DiagnosticOptions ());
294- Clang.setDiagnostics (Diags.get ());
295-
296- FileManager *FM = Clang.createFileManager (VFS);
297- Clang.createSourceManager (*FM);
298-
299- if (!Clang.createTarget ())
300- return false ;
301-
302- assert (Clang.getHeaderSearchOptsPtr ());
303- adjustHeaderSearchOptions (Clang.getHeaderSearchOpts ());
304- // Since we don't need to compile the source code actually, the TU kind here
305- // doesn't matter.
306- Clang.createPreprocessor (TU_Complete);
307- Clang.getHeaderSearchOpts ().ForceCheckCXX20ModulesInputFiles = true ;
308- Clang.getHeaderSearchOpts ().ValidateASTInputFilesContent = true ;
309-
310- // Following the practice of clang's driver to suppres the checking for ODR
311- // violation in GMF.
312- // See
313- // https://clang.llvm.org/docs/StandardCPlusPlusModules.html#object-definition-consistency
314- // for example.
315- Clang.getLangOpts ().SkipODRCheckInGMF = true ;
316-
317- Clang.createASTReader ();
318- for (auto &RequiredModule : RequiredModules) {
319- llvm::StringRef BMIPath = RequiredModule.ModuleFilePath ;
320- // FIXME: Loading BMI fully is too heavy considering something cheaply to
321- // check if we can reuse the BMI.
322- auto ReadResult =
323- Clang.getASTReader ()->ReadAST (BMIPath, serialization::MK_MainFile,
324- SourceLocation (), ASTReader::ARR_None);
325-
326- if (ReadResult != ASTReader::Success) {
327- elog (" Can't reuse {0}: {1}" , BMIPath, ReadResult);
328- return false ;
329- }
330- }
331-
332- return true ;
347+ SmallVector<StringRef> BMIPaths;
348+ for (auto &MF : RequiredModules)
349+ BMIPaths.push_back (MF.ModuleFilePath );
350+ return IsModuleFilesUpToDate (BMIPaths, *this );
333351}
334352
335353} // namespace clangd
0 commit comments