Skip to content

Commit

Permalink
[clangd] [Modules] Use ASTReader directly in IsModuleFileUpToDate (#1…
Browse files Browse the repository at this point in the history
…13879)

@kadircet mentioned in
448d8fa#diff-fb3ba8a781117ff04736f951a274812cb7ad1678f9d71d4d91870b711ab45da0L285
that:

> this is definitely a functional change, clangd is used in environments
that solely relies on VFS, and doesn't depend on ASTUnit at all.

> right now this is both introducing a dependency on ASTUnit, and making
all the logical IO physical instead. can you instead use the regular
compiler utilities in clangd, and get the astreader from
CompilerInstance directly, which is VFS-aware, and doesn't depend on
ASTUnit ?

This tries to resolve the problem by creating ASTReader directly and use
VFS to create the FileManager.
  • Loading branch information
ChuanqiXu9 authored Oct 31, 2024
1 parent 3243e3d commit e9b7fe8
Showing 1 changed file with 41 additions and 22 deletions.
63 changes: 41 additions & 22 deletions clang-tools-extra/clangd/ModulesBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/InMemoryModuleCache.h"

namespace clang {
namespace clangd {
Expand Down Expand Up @@ -127,50 +128,68 @@ struct ModuleFile {
std::string ModuleFilePath;
};

bool IsModuleFileUpToDate(
PathRef ModuleFilePath,
const PrerequisiteModules &RequisiteModules) {
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
CompilerInstance::createDiagnostics(new DiagnosticOptions());

bool IsModuleFileUpToDate(PathRef ModuleFilePath,
const PrerequisiteModules &RequisiteModules,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
auto HSOpts = std::make_shared<HeaderSearchOptions>();
RequisiteModules.adjustHeaderSearchOptions(*HSOpts);
HSOpts->ForceCheckCXX20ModulesInputFiles = true;
HSOpts->ValidateASTInputFilesContent = true;

clang::clangd::IgnoreDiagnostics IgnoreDiags;
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
CompilerInstance::createDiagnostics(new DiagnosticOptions, &IgnoreDiags,
/*ShouldOwnClient=*/false);

LangOptions LangOpts;
LangOpts.SkipODRCheckInGMF = true;

FileManager FileMgr(FileSystemOptions(), VFS);

SourceManager SourceMgr(*Diags, FileMgr);

HeaderSearch HeaderInfo(HSOpts, SourceMgr, *Diags, LangOpts,
/*Target=*/nullptr);

TrivialModuleLoader ModuleLoader;
Preprocessor PP(std::make_shared<PreprocessorOptions>(), *Diags, LangOpts,
SourceMgr, HeaderInfo, ModuleLoader);

IntrusiveRefCntPtr<InMemoryModuleCache> ModuleCache = new InMemoryModuleCache;
PCHContainerOperations PCHOperations;
std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
ModuleFilePath.str(), PCHOperations.getRawReader(), ASTUnit::LoadASTOnly,
Diags, FileSystemOptions(), std::move(HSOpts));
ASTReader Reader(PP, *ModuleCache, /*ASTContext=*/nullptr,
PCHOperations.getRawReader(), {});

if (!Unit)
return false;
// We don't need any listener here. By default it will use a validator
// listener.
Reader.setListener(nullptr);

auto Reader = Unit->getASTReader();
if (!Reader)
if (Reader.ReadAST(ModuleFilePath, serialization::MK_MainFile,
SourceLocation(),
ASTReader::ARR_None) != ASTReader::Success)
return false;

bool UpToDate = true;
Reader->getModuleManager().visit([&](serialization::ModuleFile &MF) -> bool {
Reader->visitInputFiles(
Reader.getModuleManager().visit([&](serialization::ModuleFile &MF) -> bool {
Reader.visitInputFiles(
MF, /*IncludeSystem=*/false, /*Complain=*/false,
[&](const serialization::InputFile &IF, bool isSystem) {
if (!IF.getFile() || IF.isOutOfDate())
UpToDate = false;
});

return !UpToDate;
});

return UpToDate;
}

bool IsModuleFilesUpToDate(
llvm::SmallVector<PathRef> ModuleFilePaths,
const PrerequisiteModules &RequisiteModules) {
return llvm::all_of(ModuleFilePaths, [&RequisiteModules](auto ModuleFilePath) {
return IsModuleFileUpToDate(ModuleFilePath, RequisiteModules);
});
const PrerequisiteModules &RequisiteModules,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
return llvm::all_of(
ModuleFilePaths, [&RequisiteModules, VFS](auto ModuleFilePath) {
return IsModuleFileUpToDate(ModuleFilePath, RequisiteModules, VFS);
});
}

// StandalonePrerequisiteModules - stands for PrerequisiteModules for which all
Expand Down Expand Up @@ -347,7 +366,7 @@ bool StandalonePrerequisiteModules::canReuse(
SmallVector<StringRef> BMIPaths;
for (auto &MF : RequiredModules)
BMIPaths.push_back(MF.ModuleFilePath);
return IsModuleFilesUpToDate(BMIPaths, *this);
return IsModuleFilesUpToDate(BMIPaths, *this, VFS);
}

} // namespace clangd
Expand Down

0 comments on commit e9b7fe8

Please sign in to comment.