12#include "clang/Frontend/FrontendAction.h"
13#include "clang/Frontend/FrontendActions.h"
14#include "clang/Serialization/ASTReader.h"
36 llvm::SmallString<128> HashedPrefix = llvm::sys::path::filename(
MainFile);
39 HashedPrefix += std::to_string(llvm::hash_value(
MainFile));
41 llvm::SmallString<256> ResultPattern;
43 llvm::sys::path::system_temp_directory(
true,
46 llvm::sys::path::append(ResultPattern,
"clangd");
47 llvm::sys::path::append(ResultPattern,
"module_files");
49 llvm::sys::path::append(ResultPattern, HashedPrefix);
51 ResultPattern.append(
"-%%-%%-%%-%%-%%-%%");
53 llvm::SmallString<256> Result;
54 llvm::sys::fs::createUniquePath(ResultPattern, Result,
57 llvm::sys::fs::create_directories(Result);
62std::string getModuleFilePath(llvm::StringRef
ModuleName,
65 auto [PrimaryModuleName, PartitionName] =
ModuleName.split(
':');
67 if (!PartitionName.empty()) {
78class FailedPrerequisiteModules :
public PrerequisiteModules {
80 ~FailedPrerequisiteModules()
override =
default;
84 void adjustHeaderSearchOptions(HeaderSearchOptions &Options)
const override {
89 canReuse(
const CompilerInvocation &
CI,
90 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>)
const override {
104class StandalonePrerequisiteModules :
public PrerequisiteModules {
106 StandalonePrerequisiteModules() =
default;
108 StandalonePrerequisiteModules(
const StandalonePrerequisiteModules &) =
delete;
109 StandalonePrerequisiteModules
110 operator=(
const StandalonePrerequisiteModules &) =
delete;
111 StandalonePrerequisiteModules(StandalonePrerequisiteModules &&) =
delete;
112 StandalonePrerequisiteModules
113 operator=(StandalonePrerequisiteModules &&) =
delete;
115 ~StandalonePrerequisiteModules()
override =
default;
117 void adjustHeaderSearchOptions(HeaderSearchOptions &Options)
const override {
119 for (
auto &RequiredModule : RequiredModules)
120 Options.PrebuiltModuleFiles.insert_or_assign(
121 RequiredModule.ModuleName, RequiredModule.ModuleFilePath);
124 bool canReuse(
const CompilerInvocation &
CI,
125 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>)
const override;
127 bool isModuleUnitBuilt(llvm::StringRef
ModuleName)
const {
131 void addModuleFile(llvm::StringRef
ModuleName,
139 ModuleFile(llvm::StringRef ModuleName,
PathRef ModuleFilePath)
142 ModuleFile(
const ModuleFile &) =
delete;
143 ModuleFile operator=(
const ModuleFile &) =
delete;
146 ModuleFile(ModuleFile &&Other)
150 ModuleFile &operator=(ModuleFile &&Other) =
delete;
154 llvm::sys::fs::remove(ModuleFilePath);
161 llvm::SmallVector<ModuleFile, 8> RequiredModules;
163 llvm::StringSet<> BuiltModuleNames;
168llvm::Error buildModuleFile(llvm::StringRef
ModuleName,
169 const GlobalCompilationDatabase &CDB,
170 const ThreadsafeFS &TFS, ProjectModules &MDB,
172 StandalonePrerequisiteModules &BuiltModuleFiles) {
173 if (BuiltModuleFiles.isModuleUnitBuilt(
ModuleName))
174 return llvm::Error::success();
184 if (ModuleUnitFileName.empty())
185 return llvm::createStringError(
"Failed to get the primary source");
188 auto Cmd = CDB.getCompileCommand(ModuleUnitFileName);
190 return llvm::createStringError(
191 llvm::formatv(
"No compile command for {0}", ModuleUnitFileName));
193 for (
auto &RequiredModuleName : MDB.getRequiredModules(ModuleUnitFileName)) {
195 if (llvm::Error Err = buildModuleFile(RequiredModuleName, CDB, TFS, MDB,
196 ModuleFilesPrefix, BuiltModuleFiles))
197 return llvm::createStringError(
198 llvm::formatv(
"Failed to build dependency {0}: {1}",
199 RequiredModuleName, llvm::toString(std::move(Err))));
202 Cmd->Output = getModuleFilePath(
ModuleName, ModuleFilesPrefix);
211 return llvm::createStringError(
"Failed to build compiler invocation");
216 return llvm::createStringError(
"Failed to create buffer");
220 CI->getLangOpts().SkipODRCheckInGMF =
true;
225 CI->getHeaderSearchOpts().ValidateASTInputFilesContent =
true;
227 BuiltModuleFiles.adjustHeaderSearchOptions(
CI->getHeaderSearchOpts());
234 return llvm::createStringError(
"Failed to prepare compiler instance");
236 GenerateReducedModuleInterfaceAction
Action;
239 if (
Clang->getDiagnostics().hasErrorOccurred())
240 return llvm::createStringError(
"Compilation failed");
243 return llvm::Error::success();
247std::unique_ptr<PrerequisiteModules>
250 std::unique_ptr<ProjectModules> MDB = CDB.getProjectModules(
File);
252 elog(
"Failed to get Project Modules information for {0}",
File);
253 return std::make_unique<FailedPrerequisiteModules>();
256 std::vector<std::string> RequiredModuleNames = MDB->getRequiredModules(
File);
257 if (RequiredModuleNames.empty())
258 return std::make_unique<StandalonePrerequisiteModules>();
260 llvm::SmallString<256> ModuleFilesPrefix = getUniqueModuleFilesPath(
File);
262 log(
"Trying to build required modules for {0} in {1}",
File,
265 auto RequiredModules = std::make_unique<StandalonePrerequisiteModules>();
267 for (llvm::StringRef RequiredModuleName : RequiredModuleNames) {
269 if (llvm::Error Err =
270 buildModuleFile(RequiredModuleName, CDB, TFS, *MDB.get(),
271 ModuleFilesPrefix, *RequiredModules.get())) {
272 elog(
"Failed to build module {0}; due to {1}", RequiredModuleName,
274 return std::make_unique<FailedPrerequisiteModules>();
278 log(
"Built required modules for {0} in {1}",
File, ModuleFilesPrefix);
280 return std::move(RequiredModules);
283bool StandalonePrerequisiteModules::canReuse(
284 const CompilerInvocation &
CI,
285 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
const {
286 if (RequiredModules.empty())
289 CompilerInstance
Clang;
291 Clang.setInvocation(std::make_shared<CompilerInvocation>(
CI));
292 IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
293 CompilerInstance::createDiagnostics(
new DiagnosticOptions());
294 Clang.setDiagnostics(Diags.get());
296 FileManager *FM =
Clang.createFileManager(VFS);
297 Clang.createSourceManager(*FM);
299 if (!
Clang.createTarget())
302 assert(
Clang.getHeaderSearchOptsPtr());
303 adjustHeaderSearchOptions(
Clang.getHeaderSearchOpts());
306 Clang.createPreprocessor(TU_Complete);
307 Clang.getHeaderSearchOpts().ForceCheckCXX20ModulesInputFiles =
true;
308 Clang.getHeaderSearchOpts().ValidateASTInputFilesContent =
true;
315 Clang.getLangOpts().SkipODRCheckInGMF =
true;
317 Clang.createASTReader();
318 for (
auto &RequiredModule : RequiredModules) {
319 llvm::StringRef BMIPath = RequiredModule.ModuleFilePath;
323 Clang.getASTReader()->ReadAST(BMIPath, serialization::MK_MainFile,
324 SourceLocation(), ASTReader::ARR_None);
326 if (ReadResult != ASTReader::Success) {
327 elog(
"Can't reuse {0}: {1}", BMIPath, ReadResult);
std::string ModuleFilePath
std::unique_ptr< CompilerInvocation > CI
std::unique_ptr< PrerequisiteModules > buildPrerequisiteModulesFor(PathRef File, const ThreadsafeFS &TFS) const
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > view(std::nullopt_t CWD) const
Obtain a vfs::FileSystem with an arbitrary initial working directory.
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.
static const char * toString(OffsetEncoding OE)
std::unique_ptr< CompilerInstance > prepareCompilerInstance(std::unique_ptr< clang::CompilerInvocation > CI, const PrecompiledPreamble *Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, DiagnosticConsumer &DiagsClient)
void log(const char *Fmt, Ts &&... Vals)
llvm::StringRef PathRef
A typedef to represent a ref to file path.
void elog(const char *Fmt, Ts &&... Vals)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//