Skip to content

Commit 448d8fa

Browse files
committed
[NFC] [clangd] [Modules] Extract ModuleFile class and IsModuleFileUpToDate function
This patch extracts ModuleFile class from StandalonePrerequisiteModules so that we can reuse it further. And also we implement IsModuleFileUpToDate function to implement StandalonePrerequisiteModules::CanReuse. Both of them aims to ease the future improvements to the support of modules in clangd. And both of them should be NFC.
1 parent a527248 commit 448d8fa

File tree

1 file changed

+86
-67
lines changed

1 file changed

+86
-67
lines changed

clang-tools-extra/clangd/ModulesBuilder.cpp

Lines changed: 86 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,88 @@ 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+
if (RequisiteModules)
138+
RequisiteModules->adjustHeaderSearchOptions(*HSOpts);
139+
HSOpts->ForceCheckCXX20ModulesInputFiles = true;
140+
HSOpts->ValidateASTInputFilesContent = true;
141+
142+
PCHContainerOperations PCHOperations;
143+
std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
144+
ModuleFilePath.str(), PCHOperations.getRawReader(), ASTUnit::LoadASTOnly,
145+
Diags, FileSystemOptions(), std::move(HSOpts));
146+
147+
if (!Unit)
148+
return false;
149+
150+
auto Reader = Unit->getASTReader();
151+
if (!Reader)
152+
return false;
153+
154+
bool UpToDate = true;
155+
Reader->getModuleManager().visit([&](serialization::ModuleFile &MF) -> bool {
156+
Reader->visitInputFiles(
157+
MF, /*IncludeSystem=*/false, /*Complain=*/false,
158+
[&](const serialization::InputFile &IF, bool isSystem) {
159+
if (!IF.getFile() || IF.isOutOfDate())
160+
UpToDate = false;
161+
});
162+
163+
return !UpToDate;
164+
});
165+
166+
return UpToDate;
167+
}
168+
169+
bool IsModuleFilesUpToDate(
170+
llvm::SmallVector<PathRef> ModuleFilePaths,
171+
const PrerequisiteModules *RequisiteModules = nullptr) {
172+
return llvm::all_of(ModuleFilePaths, [RequisiteModules](auto ModuleFilePath) {
173+
return IsModuleFileUpToDate(ModuleFilePath, RequisiteModules);
174+
});
175+
}
176+
95177
// StandalonePrerequisiteModules - stands for PrerequisiteModules for which all
96178
// the required modules are built successfully. All the module files
97179
// are owned by the StandalonePrerequisiteModules class.
@@ -135,29 +217,6 @@ class StandalonePrerequisiteModules : public PrerequisiteModules {
135217
}
136218

137219
private:
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-
161220
llvm::SmallVector<ModuleFile, 8> RequiredModules;
162221
// A helper class to speedup the query if a module is built.
163222
llvm::StringSet<> BuiltModuleNames;
@@ -286,50 +345,10 @@ bool StandalonePrerequisiteModules::canReuse(
286345
if (RequiredModules.empty())
287346
return true;
288347

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;
348+
SmallVector<StringRef> BMIPaths;
349+
for (auto &MF : RequiredModules)
350+
BMIPaths.push_back(MF.ModuleFilePath);
351+
return IsModuleFilesUpToDate(BMIPaths, this);
333352
}
334353

335354
} // namespace clangd

0 commit comments

Comments
 (0)