1200b3289SIlya Biryukov //===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===//
2200b3289SIlya Biryukov //
3200b3289SIlya Biryukov //                     The LLVM Compiler Infrastructure
4200b3289SIlya Biryukov //
5200b3289SIlya Biryukov // This file is distributed under the University of Illinois Open Source
6200b3289SIlya Biryukov // License. See LICENSE.TXT for details.
7200b3289SIlya Biryukov //
8200b3289SIlya Biryukov //===----------------------------------------------------------------------===//
9200b3289SIlya Biryukov //
10200b3289SIlya Biryukov // Helper class to build precompiled preamble.
11200b3289SIlya Biryukov //
12200b3289SIlya Biryukov //===----------------------------------------------------------------------===//
13200b3289SIlya Biryukov 
14200b3289SIlya Biryukov #include "clang/Frontend/PrecompiledPreamble.h"
15200b3289SIlya Biryukov #include "clang/AST/DeclObjC.h"
16200b3289SIlya Biryukov #include "clang/Basic/TargetInfo.h"
17200b3289SIlya Biryukov #include "clang/Basic/VirtualFileSystem.h"
18200b3289SIlya Biryukov #include "clang/Frontend/CompilerInstance.h"
19200b3289SIlya Biryukov #include "clang/Frontend/CompilerInvocation.h"
20200b3289SIlya Biryukov #include "clang/Frontend/FrontendActions.h"
21200b3289SIlya Biryukov #include "clang/Frontend/FrontendOptions.h"
22200b3289SIlya Biryukov #include "clang/Lex/Lexer.h"
23200b3289SIlya Biryukov #include "clang/Lex/PreprocessorOptions.h"
24200b3289SIlya Biryukov #include "clang/Serialization/ASTWriter.h"
25200b3289SIlya Biryukov #include "llvm/ADT/StringExtras.h"
26200b3289SIlya Biryukov #include "llvm/ADT/StringSet.h"
27200b3289SIlya Biryukov #include "llvm/Support/CrashRecoveryContext.h"
28200b3289SIlya Biryukov #include "llvm/Support/FileSystem.h"
29200b3289SIlya Biryukov #include "llvm/Support/Mutex.h"
30200b3289SIlya Biryukov #include "llvm/Support/MutexGuard.h"
31*b88de416SIlya Biryukov #include "llvm/Support/Process.h"
32200b3289SIlya Biryukov 
33200b3289SIlya Biryukov using namespace clang;
34200b3289SIlya Biryukov 
35200b3289SIlya Biryukov namespace {
36200b3289SIlya Biryukov 
37200b3289SIlya Biryukov /// Keeps a track of files to be deleted in destructor.
38200b3289SIlya Biryukov class TemporaryFiles {
39200b3289SIlya Biryukov public:
40200b3289SIlya Biryukov   // A static instance to be used by all clients.
41200b3289SIlya Biryukov   static TemporaryFiles &getInstance();
42200b3289SIlya Biryukov 
43200b3289SIlya Biryukov private:
44200b3289SIlya Biryukov   // Disallow constructing the class directly.
45200b3289SIlya Biryukov   TemporaryFiles() = default;
46200b3289SIlya Biryukov   // Disallow copy.
47200b3289SIlya Biryukov   TemporaryFiles(const TemporaryFiles &) = delete;
48200b3289SIlya Biryukov 
49200b3289SIlya Biryukov public:
50200b3289SIlya Biryukov   ~TemporaryFiles();
51200b3289SIlya Biryukov 
52200b3289SIlya Biryukov   /// Adds \p File to a set of tracked files.
53200b3289SIlya Biryukov   void addFile(StringRef File);
54200b3289SIlya Biryukov 
55200b3289SIlya Biryukov   /// Remove \p File from disk and from the set of tracked files.
56200b3289SIlya Biryukov   void removeFile(StringRef File);
57200b3289SIlya Biryukov 
58200b3289SIlya Biryukov private:
59200b3289SIlya Biryukov   llvm::sys::SmartMutex<false> Mutex;
60200b3289SIlya Biryukov   llvm::StringSet<> Files;
61200b3289SIlya Biryukov };
62200b3289SIlya Biryukov 
63200b3289SIlya Biryukov TemporaryFiles &TemporaryFiles::getInstance() {
64200b3289SIlya Biryukov   static TemporaryFiles Instance;
65200b3289SIlya Biryukov   return Instance;
66200b3289SIlya Biryukov }
67200b3289SIlya Biryukov 
68200b3289SIlya Biryukov TemporaryFiles::~TemporaryFiles() {
69200b3289SIlya Biryukov   llvm::MutexGuard Guard(Mutex);
70200b3289SIlya Biryukov   for (const auto &File : Files)
71200b3289SIlya Biryukov     llvm::sys::fs::remove(File.getKey());
72200b3289SIlya Biryukov }
73200b3289SIlya Biryukov 
74200b3289SIlya Biryukov void TemporaryFiles::addFile(StringRef File) {
75200b3289SIlya Biryukov   llvm::MutexGuard Guard(Mutex);
76200b3289SIlya Biryukov   auto IsInserted = Files.insert(File).second;
7753dd644cSHaojian Wu   (void)IsInserted;
78200b3289SIlya Biryukov   assert(IsInserted && "File has already been added");
79200b3289SIlya Biryukov }
80200b3289SIlya Biryukov 
81200b3289SIlya Biryukov void TemporaryFiles::removeFile(StringRef File) {
82200b3289SIlya Biryukov   llvm::MutexGuard Guard(Mutex);
83200b3289SIlya Biryukov   auto WasPresent = Files.erase(File);
8453dd644cSHaojian Wu   (void)WasPresent;
85200b3289SIlya Biryukov   assert(WasPresent && "File was not tracked");
86200b3289SIlya Biryukov   llvm::sys::fs::remove(File);
87200b3289SIlya Biryukov }
88200b3289SIlya Biryukov 
89200b3289SIlya Biryukov class PreambleMacroCallbacks : public PPCallbacks {
90200b3289SIlya Biryukov public:
91200b3289SIlya Biryukov   PreambleMacroCallbacks(PreambleCallbacks &Callbacks) : Callbacks(Callbacks) {}
92200b3289SIlya Biryukov 
93200b3289SIlya Biryukov   void MacroDefined(const Token &MacroNameTok,
94200b3289SIlya Biryukov                     const MacroDirective *MD) override {
95200b3289SIlya Biryukov     Callbacks.HandleMacroDefined(MacroNameTok, MD);
96200b3289SIlya Biryukov   }
97200b3289SIlya Biryukov 
98200b3289SIlya Biryukov private:
99200b3289SIlya Biryukov   PreambleCallbacks &Callbacks;
100200b3289SIlya Biryukov };
101200b3289SIlya Biryukov 
102200b3289SIlya Biryukov class PrecompilePreambleAction : public ASTFrontendAction {
103200b3289SIlya Biryukov public:
104200b3289SIlya Biryukov   PrecompilePreambleAction(PreambleCallbacks &Callbacks)
105200b3289SIlya Biryukov       : Callbacks(Callbacks) {}
106200b3289SIlya Biryukov 
107200b3289SIlya Biryukov   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
108200b3289SIlya Biryukov                                                  StringRef InFile) override;
109200b3289SIlya Biryukov 
110200b3289SIlya Biryukov   bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
111200b3289SIlya Biryukov 
112200b3289SIlya Biryukov   void setEmittedPreamblePCH(ASTWriter &Writer) {
113200b3289SIlya Biryukov     this->HasEmittedPreamblePCH = true;
114200b3289SIlya Biryukov     Callbacks.AfterPCHEmitted(Writer);
115200b3289SIlya Biryukov   }
116200b3289SIlya Biryukov 
117200b3289SIlya Biryukov   bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
118200b3289SIlya Biryukov   bool hasCodeCompletionSupport() const override { return false; }
119200b3289SIlya Biryukov   bool hasASTFileSupport() const override { return false; }
120200b3289SIlya Biryukov   TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
121200b3289SIlya Biryukov 
122200b3289SIlya Biryukov private:
123200b3289SIlya Biryukov   friend class PrecompilePreambleConsumer;
124200b3289SIlya Biryukov 
125200b3289SIlya Biryukov   bool HasEmittedPreamblePCH = false;
126200b3289SIlya Biryukov   PreambleCallbacks &Callbacks;
127200b3289SIlya Biryukov };
128200b3289SIlya Biryukov 
129200b3289SIlya Biryukov class PrecompilePreambleConsumer : public PCHGenerator {
130200b3289SIlya Biryukov public:
131200b3289SIlya Biryukov   PrecompilePreambleConsumer(PrecompilePreambleAction &Action,
132200b3289SIlya Biryukov                              const Preprocessor &PP, StringRef isysroot,
133200b3289SIlya Biryukov                              std::unique_ptr<raw_ostream> Out)
134200b3289SIlya Biryukov       : PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(),
135200b3289SIlya Biryukov                      ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
136200b3289SIlya Biryukov                      /*AllowASTWithErrors=*/true),
137200b3289SIlya Biryukov         Action(Action), Out(std::move(Out)) {}
138200b3289SIlya Biryukov 
139200b3289SIlya Biryukov   bool HandleTopLevelDecl(DeclGroupRef DG) override {
140200b3289SIlya Biryukov     Action.Callbacks.HandleTopLevelDecl(DG);
141200b3289SIlya Biryukov     return true;
142200b3289SIlya Biryukov   }
143200b3289SIlya Biryukov 
144200b3289SIlya Biryukov   void HandleTranslationUnit(ASTContext &Ctx) override {
145200b3289SIlya Biryukov     PCHGenerator::HandleTranslationUnit(Ctx);
146200b3289SIlya Biryukov     if (!hasEmittedPCH())
147200b3289SIlya Biryukov       return;
148200b3289SIlya Biryukov 
149200b3289SIlya Biryukov     // Write the generated bitstream to "Out".
150200b3289SIlya Biryukov     *Out << getPCH();
151200b3289SIlya Biryukov     // Make sure it hits disk now.
152200b3289SIlya Biryukov     Out->flush();
153200b3289SIlya Biryukov     // Free the buffer.
154200b3289SIlya Biryukov     llvm::SmallVector<char, 0> Empty;
155200b3289SIlya Biryukov     getPCH() = std::move(Empty);
156200b3289SIlya Biryukov 
157200b3289SIlya Biryukov     Action.setEmittedPreamblePCH(getWriter());
158200b3289SIlya Biryukov   }
159200b3289SIlya Biryukov 
160200b3289SIlya Biryukov private:
161200b3289SIlya Biryukov   PrecompilePreambleAction &Action;
162200b3289SIlya Biryukov   std::unique_ptr<raw_ostream> Out;
163200b3289SIlya Biryukov };
164200b3289SIlya Biryukov 
165200b3289SIlya Biryukov std::unique_ptr<ASTConsumer>
166200b3289SIlya Biryukov PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
167200b3289SIlya Biryukov 
168200b3289SIlya Biryukov                                             StringRef InFile) {
169200b3289SIlya Biryukov   std::string Sysroot;
170200b3289SIlya Biryukov   std::string OutputFile;
171200b3289SIlya Biryukov   std::unique_ptr<raw_ostream> OS =
172200b3289SIlya Biryukov       GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
173200b3289SIlya Biryukov                                                      OutputFile);
174200b3289SIlya Biryukov   if (!OS)
175200b3289SIlya Biryukov     return nullptr;
176200b3289SIlya Biryukov 
177200b3289SIlya Biryukov   if (!CI.getFrontendOpts().RelocatablePCH)
178200b3289SIlya Biryukov     Sysroot.clear();
179200b3289SIlya Biryukov 
180200b3289SIlya Biryukov   CI.getPreprocessor().addPPCallbacks(
181200b3289SIlya Biryukov       llvm::make_unique<PreambleMacroCallbacks>(Callbacks));
182200b3289SIlya Biryukov   return llvm::make_unique<PrecompilePreambleConsumer>(
183200b3289SIlya Biryukov       *this, CI.getPreprocessor(), Sysroot, std::move(OS));
184200b3289SIlya Biryukov }
185200b3289SIlya Biryukov 
186200b3289SIlya Biryukov template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
187200b3289SIlya Biryukov   if (!Val)
188200b3289SIlya Biryukov     return false;
189200b3289SIlya Biryukov   Output = std::move(*Val);
190200b3289SIlya Biryukov   return true;
191200b3289SIlya Biryukov }
192200b3289SIlya Biryukov 
193200b3289SIlya Biryukov } // namespace
194200b3289SIlya Biryukov 
195200b3289SIlya Biryukov PreambleBounds clang::ComputePreambleBounds(const LangOptions &LangOpts,
196200b3289SIlya Biryukov                                             llvm::MemoryBuffer *Buffer,
197200b3289SIlya Biryukov                                             unsigned MaxLines) {
198200b3289SIlya Biryukov   auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines);
199200b3289SIlya Biryukov   return PreambleBounds(Pre.first, Pre.second);
200200b3289SIlya Biryukov }
201200b3289SIlya Biryukov 
202200b3289SIlya Biryukov llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
203200b3289SIlya Biryukov     const CompilerInvocation &Invocation,
204200b3289SIlya Biryukov     const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
205200b3289SIlya Biryukov     DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
206200b3289SIlya Biryukov     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
207200b3289SIlya Biryukov     PreambleCallbacks &Callbacks) {
208200b3289SIlya Biryukov   assert(VFS && "VFS is null");
209200b3289SIlya Biryukov 
210200b3289SIlya Biryukov   if (!Bounds.Size)
211200b3289SIlya Biryukov     return BuildPreambleError::PreambleIsEmpty;
212200b3289SIlya Biryukov 
213200b3289SIlya Biryukov   auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
214200b3289SIlya Biryukov   FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
215200b3289SIlya Biryukov   PreprocessorOptions &PreprocessorOpts =
216200b3289SIlya Biryukov       PreambleInvocation->getPreprocessorOpts();
217200b3289SIlya Biryukov 
218200b3289SIlya Biryukov   // Create a temporary file for the precompiled preamble. In rare
219200b3289SIlya Biryukov   // circumstances, this can fail.
220200b3289SIlya Biryukov   llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile =
221200b3289SIlya Biryukov       PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile();
222200b3289SIlya Biryukov   if (!PreamblePCHFile)
223200b3289SIlya Biryukov     return BuildPreambleError::CouldntCreateTempFile;
224200b3289SIlya Biryukov 
225200b3289SIlya Biryukov   // Save the preamble text for later; we'll need to compare against it for
226200b3289SIlya Biryukov   // subsequent reparses.
227200b3289SIlya Biryukov   std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(),
228200b3289SIlya Biryukov                                   MainFileBuffer->getBufferStart() +
229200b3289SIlya Biryukov                                       Bounds.Size);
230200b3289SIlya Biryukov   bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine;
231200b3289SIlya Biryukov 
232200b3289SIlya Biryukov   // Tell the compiler invocation to generate a temporary precompiled header.
233200b3289SIlya Biryukov   FrontendOpts.ProgramAction = frontend::GeneratePCH;
234200b3289SIlya Biryukov   // FIXME: Generate the precompiled header into memory?
235200b3289SIlya Biryukov   FrontendOpts.OutputFile = PreamblePCHFile->getFilePath();
236200b3289SIlya Biryukov   PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
237200b3289SIlya Biryukov   PreprocessorOpts.PrecompiledPreambleBytes.second = false;
238200b3289SIlya Biryukov 
239200b3289SIlya Biryukov   // Create the compiler instance to use for building the precompiled preamble.
240200b3289SIlya Biryukov   std::unique_ptr<CompilerInstance> Clang(
241200b3289SIlya Biryukov       new CompilerInstance(std::move(PCHContainerOps)));
242200b3289SIlya Biryukov 
243200b3289SIlya Biryukov   // Recover resources if we crash before exiting this method.
244200b3289SIlya Biryukov   llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
245200b3289SIlya Biryukov       Clang.get());
246200b3289SIlya Biryukov 
247200b3289SIlya Biryukov   Clang->setInvocation(std::move(PreambleInvocation));
248200b3289SIlya Biryukov   Clang->setDiagnostics(&Diagnostics);
249200b3289SIlya Biryukov 
250200b3289SIlya Biryukov   // Create the target instance.
251200b3289SIlya Biryukov   Clang->setTarget(TargetInfo::CreateTargetInfo(
252200b3289SIlya Biryukov       Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
253200b3289SIlya Biryukov   if (!Clang->hasTarget())
254200b3289SIlya Biryukov     return BuildPreambleError::CouldntCreateTargetInfo;
255200b3289SIlya Biryukov 
256200b3289SIlya Biryukov   // Inform the target of the language options.
257200b3289SIlya Biryukov   //
258200b3289SIlya Biryukov   // FIXME: We shouldn't need to do this, the target should be immutable once
259200b3289SIlya Biryukov   // created. This complexity should be lifted elsewhere.
260200b3289SIlya Biryukov   Clang->getTarget().adjust(Clang->getLangOpts());
261200b3289SIlya Biryukov 
262200b3289SIlya Biryukov   assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
263200b3289SIlya Biryukov          "Invocation must have exactly one source file!");
264200b3289SIlya Biryukov   assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
265200b3289SIlya Biryukov              InputKind::Source &&
266200b3289SIlya Biryukov          "FIXME: AST inputs not yet supported here!");
267200b3289SIlya Biryukov   assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
268200b3289SIlya Biryukov              InputKind::LLVM_IR &&
269200b3289SIlya Biryukov          "IR inputs not support here!");
270200b3289SIlya Biryukov 
271200b3289SIlya Biryukov   // Clear out old caches and data.
272200b3289SIlya Biryukov   Diagnostics.Reset();
273200b3289SIlya Biryukov   ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts());
274200b3289SIlya Biryukov 
275200b3289SIlya Biryukov   VFS =
276200b3289SIlya Biryukov       createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS);
277200b3289SIlya Biryukov   if (!VFS)
278200b3289SIlya Biryukov     return BuildPreambleError::CouldntCreateVFSOverlay;
279200b3289SIlya Biryukov 
280200b3289SIlya Biryukov   // Create a file manager object to provide access to and cache the filesystem.
281200b3289SIlya Biryukov   Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
282200b3289SIlya Biryukov 
283200b3289SIlya Biryukov   // Create the source manager.
284200b3289SIlya Biryukov   Clang->setSourceManager(
285200b3289SIlya Biryukov       new SourceManager(Diagnostics, Clang->getFileManager()));
286200b3289SIlya Biryukov 
287200b3289SIlya Biryukov   auto PreambleDepCollector = std::make_shared<DependencyCollector>();
288200b3289SIlya Biryukov   Clang->addDependencyCollector(PreambleDepCollector);
289200b3289SIlya Biryukov 
290200b3289SIlya Biryukov   // Remap the main source file to the preamble buffer.
291200b3289SIlya Biryukov   StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
292200b3289SIlya Biryukov   auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
293200b3289SIlya Biryukov       MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
294200b3289SIlya Biryukov   if (PreprocessorOpts.RetainRemappedFileBuffers) {
295200b3289SIlya Biryukov     // MainFileBuffer will be deleted by unique_ptr after leaving the method.
296200b3289SIlya Biryukov     PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get());
297200b3289SIlya Biryukov   } else {
298200b3289SIlya Biryukov     // In that case, remapped buffer will be deleted by CompilerInstance on
299200b3289SIlya Biryukov     // BeginSourceFile, so we call release() to avoid double deletion.
300200b3289SIlya Biryukov     PreprocessorOpts.addRemappedFile(MainFilePath,
301200b3289SIlya Biryukov                                      PreambleInputBuffer.release());
302200b3289SIlya Biryukov   }
303200b3289SIlya Biryukov 
304200b3289SIlya Biryukov   std::unique_ptr<PrecompilePreambleAction> Act;
305200b3289SIlya Biryukov   Act.reset(new PrecompilePreambleAction(Callbacks));
306200b3289SIlya Biryukov   if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
307200b3289SIlya Biryukov     return BuildPreambleError::BeginSourceFileFailed;
308200b3289SIlya Biryukov 
309200b3289SIlya Biryukov   Act->Execute();
310200b3289SIlya Biryukov 
311200b3289SIlya Biryukov   // Run the callbacks.
312200b3289SIlya Biryukov   Callbacks.AfterExecute(*Clang);
313200b3289SIlya Biryukov 
314200b3289SIlya Biryukov   Act->EndSourceFile();
315200b3289SIlya Biryukov 
316200b3289SIlya Biryukov   if (!Act->hasEmittedPreamblePCH())
317200b3289SIlya Biryukov     return BuildPreambleError::CouldntEmitPCH;
318200b3289SIlya Biryukov 
319200b3289SIlya Biryukov   // Keep track of all of the files that the source manager knows about,
320200b3289SIlya Biryukov   // so we can verify whether they have changed or not.
321200b3289SIlya Biryukov   llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
322200b3289SIlya Biryukov 
323200b3289SIlya Biryukov   SourceManager &SourceMgr = Clang->getSourceManager();
324200b3289SIlya Biryukov   for (auto &Filename : PreambleDepCollector->getDependencies()) {
325200b3289SIlya Biryukov     const FileEntry *File = Clang->getFileManager().getFile(Filename);
326200b3289SIlya Biryukov     if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
327200b3289SIlya Biryukov       continue;
328200b3289SIlya Biryukov     if (time_t ModTime = File->getModificationTime()) {
329200b3289SIlya Biryukov       FilesInPreamble[File->getName()] =
330200b3289SIlya Biryukov           PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
331200b3289SIlya Biryukov                                                                ModTime);
332200b3289SIlya Biryukov     } else {
333200b3289SIlya Biryukov       llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
334200b3289SIlya Biryukov       FilesInPreamble[File->getName()] =
335200b3289SIlya Biryukov           PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
336200b3289SIlya Biryukov     }
337200b3289SIlya Biryukov   }
338200b3289SIlya Biryukov 
339200b3289SIlya Biryukov   return PrecompiledPreamble(
340200b3289SIlya Biryukov       std::move(*PreamblePCHFile), std::move(PreambleBytes),
341200b3289SIlya Biryukov       PreambleEndsAtStartOfLine, std::move(FilesInPreamble));
342200b3289SIlya Biryukov }
343200b3289SIlya Biryukov 
344200b3289SIlya Biryukov PreambleBounds PrecompiledPreamble::getBounds() const {
345200b3289SIlya Biryukov   return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
346200b3289SIlya Biryukov }
347200b3289SIlya Biryukov 
348200b3289SIlya Biryukov bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation,
349200b3289SIlya Biryukov                                    const llvm::MemoryBuffer *MainFileBuffer,
350200b3289SIlya Biryukov                                    PreambleBounds Bounds,
351200b3289SIlya Biryukov                                    vfs::FileSystem *VFS) const {
352200b3289SIlya Biryukov 
353200b3289SIlya Biryukov   assert(
354200b3289SIlya Biryukov       Bounds.Size <= MainFileBuffer->getBufferSize() &&
355200b3289SIlya Biryukov       "Buffer is too large. Bounds were calculated from a different buffer?");
356200b3289SIlya Biryukov 
357200b3289SIlya Biryukov   auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
358200b3289SIlya Biryukov   PreprocessorOptions &PreprocessorOpts =
359200b3289SIlya Biryukov       PreambleInvocation->getPreprocessorOpts();
360200b3289SIlya Biryukov 
361200b3289SIlya Biryukov   if (!Bounds.Size)
362200b3289SIlya Biryukov     return false;
363200b3289SIlya Biryukov 
364200b3289SIlya Biryukov   // We've previously computed a preamble. Check whether we have the same
365200b3289SIlya Biryukov   // preamble now that we did before, and that there's enough space in
366200b3289SIlya Biryukov   // the main-file buffer within the precompiled preamble to fit the
367200b3289SIlya Biryukov   // new main file.
368200b3289SIlya Biryukov   if (PreambleBytes.size() != Bounds.Size ||
369200b3289SIlya Biryukov       PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
370200b3289SIlya Biryukov       memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(),
371200b3289SIlya Biryukov              Bounds.Size) != 0)
372200b3289SIlya Biryukov     return false;
373200b3289SIlya Biryukov   // The preamble has not changed. We may be able to re-use the precompiled
374200b3289SIlya Biryukov   // preamble.
375200b3289SIlya Biryukov 
376200b3289SIlya Biryukov   // Check that none of the files used by the preamble have changed.
377200b3289SIlya Biryukov   // First, make a record of those files that have been overridden via
378200b3289SIlya Biryukov   // remapping or unsaved_files.
379200b3289SIlya Biryukov   std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
380200b3289SIlya Biryukov   for (const auto &R : PreprocessorOpts.RemappedFiles) {
381200b3289SIlya Biryukov     vfs::Status Status;
382200b3289SIlya Biryukov     if (!moveOnNoError(VFS->status(R.second), Status)) {
383200b3289SIlya Biryukov       // If we can't stat the file we're remapping to, assume that something
384200b3289SIlya Biryukov       // horrible happened.
385200b3289SIlya Biryukov       return false;
386200b3289SIlya Biryukov     }
387200b3289SIlya Biryukov 
388200b3289SIlya Biryukov     OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
389200b3289SIlya Biryukov         Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
390200b3289SIlya Biryukov   }
391200b3289SIlya Biryukov 
392200b3289SIlya Biryukov   for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
393200b3289SIlya Biryukov     vfs::Status Status;
394200b3289SIlya Biryukov     if (!moveOnNoError(VFS->status(RB.first), Status))
395200b3289SIlya Biryukov       return false;
396200b3289SIlya Biryukov 
397200b3289SIlya Biryukov     OverriddenFiles[Status.getUniqueID()] =
398200b3289SIlya Biryukov         PreambleFileHash::createForMemoryBuffer(RB.second);
399200b3289SIlya Biryukov   }
400200b3289SIlya Biryukov 
401200b3289SIlya Biryukov   // Check whether anything has changed.
402200b3289SIlya Biryukov   for (const auto &F : FilesInPreamble) {
403200b3289SIlya Biryukov     vfs::Status Status;
404200b3289SIlya Biryukov     if (!moveOnNoError(VFS->status(F.first()), Status)) {
405200b3289SIlya Biryukov       // If we can't stat the file, assume that something horrible happened.
406200b3289SIlya Biryukov       return false;
407200b3289SIlya Biryukov     }
408200b3289SIlya Biryukov 
409200b3289SIlya Biryukov     std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
410200b3289SIlya Biryukov         OverriddenFiles.find(Status.getUniqueID());
411200b3289SIlya Biryukov     if (Overridden != OverriddenFiles.end()) {
412200b3289SIlya Biryukov       // This file was remapped; check whether the newly-mapped file
413200b3289SIlya Biryukov       // matches up with the previous mapping.
414200b3289SIlya Biryukov       if (Overridden->second != F.second)
415200b3289SIlya Biryukov         return false;
416200b3289SIlya Biryukov       continue;
417200b3289SIlya Biryukov     }
418200b3289SIlya Biryukov 
419200b3289SIlya Biryukov     // The file was not remapped; check whether it has changed on disk.
420200b3289SIlya Biryukov     if (Status.getSize() != uint64_t(F.second.Size) ||
421200b3289SIlya Biryukov         llvm::sys::toTimeT(Status.getLastModificationTime()) !=
422200b3289SIlya Biryukov             F.second.ModTime)
423200b3289SIlya Biryukov       return false;
424200b3289SIlya Biryukov   }
425200b3289SIlya Biryukov   return true;
426200b3289SIlya Biryukov }
427200b3289SIlya Biryukov 
428200b3289SIlya Biryukov void PrecompiledPreamble::AddImplicitPreamble(
429200b3289SIlya Biryukov     CompilerInvocation &CI, llvm::MemoryBuffer *MainFileBuffer) const {
430200b3289SIlya Biryukov   auto &PreprocessorOpts = CI.getPreprocessorOpts();
431200b3289SIlya Biryukov 
432200b3289SIlya Biryukov   // Configure ImpicitPCHInclude.
433200b3289SIlya Biryukov   PreprocessorOpts.PrecompiledPreambleBytes.first = PreambleBytes.size();
434200b3289SIlya Biryukov   PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine;
435200b3289SIlya Biryukov   PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
436200b3289SIlya Biryukov   PreprocessorOpts.DisablePCHValidation = true;
437200b3289SIlya Biryukov 
438200b3289SIlya Biryukov   // Remap main file to point to MainFileBuffer.
439200b3289SIlya Biryukov   auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
440200b3289SIlya Biryukov   PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
441200b3289SIlya Biryukov }
442200b3289SIlya Biryukov 
443200b3289SIlya Biryukov PrecompiledPreamble::PrecompiledPreamble(
444200b3289SIlya Biryukov     TempPCHFile PCHFile, std::vector<char> PreambleBytes,
445200b3289SIlya Biryukov     bool PreambleEndsAtStartOfLine,
446200b3289SIlya Biryukov     llvm::StringMap<PreambleFileHash> FilesInPreamble)
447200b3289SIlya Biryukov     : PCHFile(std::move(PCHFile)), FilesInPreamble(FilesInPreamble),
448200b3289SIlya Biryukov       PreambleBytes(std::move(PreambleBytes)),
449200b3289SIlya Biryukov       PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
450200b3289SIlya Biryukov 
451200b3289SIlya Biryukov llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
452200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
453200b3289SIlya Biryukov   // FIXME: This is a hack so that we can override the preamble file during
454200b3289SIlya Biryukov   // crash-recovery testing, which is the only case where the preamble files
455200b3289SIlya Biryukov   // are not necessarily cleaned up.
456200b3289SIlya Biryukov   const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
457200b3289SIlya Biryukov   if (TmpFile)
458200b3289SIlya Biryukov     return TempPCHFile::createFromCustomPath(TmpFile);
459200b3289SIlya Biryukov   return TempPCHFile::createInSystemTempDir("preamble", "pch");
460200b3289SIlya Biryukov }
461200b3289SIlya Biryukov 
462200b3289SIlya Biryukov llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
463200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
464200b3289SIlya Biryukov                                                         StringRef Suffix) {
465200b3289SIlya Biryukov   llvm::SmallString<64> File;
466*b88de416SIlya Biryukov   // Using a version of createTemporaryFile with a file descriptor guarantees
467*b88de416SIlya Biryukov   // that we would never get a race condition in a multi-threaded setting (i.e.,
468*b88de416SIlya Biryukov   // multiple threads getting the same temporary path).
469*b88de416SIlya Biryukov   int FD;
470*b88de416SIlya Biryukov   auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, /*ref*/ FD,
471*b88de416SIlya Biryukov                                                /*ref*/ File);
472200b3289SIlya Biryukov   if (EC)
473200b3289SIlya Biryukov     return EC;
474*b88de416SIlya Biryukov   // We only needed to make sure the file exists, close the file right away.
475*b88de416SIlya Biryukov   llvm::sys::Process::SafelyCloseFileDescriptor(FD);
476200b3289SIlya Biryukov   return TempPCHFile(std::move(File).str());
477200b3289SIlya Biryukov }
478200b3289SIlya Biryukov 
479200b3289SIlya Biryukov llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
480200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
481200b3289SIlya Biryukov   return TempPCHFile(Path.str());
482200b3289SIlya Biryukov }
483200b3289SIlya Biryukov 
484200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
485200b3289SIlya Biryukov     : FilePath(std::move(FilePath)) {
486200b3289SIlya Biryukov   TemporaryFiles::getInstance().addFile(*this->FilePath);
487200b3289SIlya Biryukov }
488200b3289SIlya Biryukov 
489200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
490200b3289SIlya Biryukov   FilePath = std::move(Other.FilePath);
491200b3289SIlya Biryukov   Other.FilePath = None;
492200b3289SIlya Biryukov }
493200b3289SIlya Biryukov 
494200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
495200b3289SIlya Biryukov operator=(TempPCHFile &&Other) {
496200b3289SIlya Biryukov   RemoveFileIfPresent();
497200b3289SIlya Biryukov 
498200b3289SIlya Biryukov   FilePath = std::move(Other.FilePath);
499200b3289SIlya Biryukov   Other.FilePath = None;
500200b3289SIlya Biryukov   return *this;
501200b3289SIlya Biryukov }
502200b3289SIlya Biryukov 
503200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
504200b3289SIlya Biryukov 
505200b3289SIlya Biryukov void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
506200b3289SIlya Biryukov   if (FilePath) {
507200b3289SIlya Biryukov     TemporaryFiles::getInstance().removeFile(*FilePath);
508200b3289SIlya Biryukov     FilePath = None;
509200b3289SIlya Biryukov   }
510200b3289SIlya Biryukov }
511200b3289SIlya Biryukov 
512200b3289SIlya Biryukov llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
513200b3289SIlya Biryukov   assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
514200b3289SIlya Biryukov   return *FilePath;
515200b3289SIlya Biryukov }
516200b3289SIlya Biryukov 
517200b3289SIlya Biryukov PrecompiledPreamble::PreambleFileHash
518200b3289SIlya Biryukov PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
519200b3289SIlya Biryukov                                                      time_t ModTime) {
520200b3289SIlya Biryukov   PreambleFileHash Result;
521200b3289SIlya Biryukov   Result.Size = Size;
522200b3289SIlya Biryukov   Result.ModTime = ModTime;
523200b3289SIlya Biryukov   Result.MD5 = {};
524200b3289SIlya Biryukov   return Result;
525200b3289SIlya Biryukov }
526200b3289SIlya Biryukov 
527200b3289SIlya Biryukov PrecompiledPreamble::PreambleFileHash
528200b3289SIlya Biryukov PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
529200b3289SIlya Biryukov     const llvm::MemoryBuffer *Buffer) {
530200b3289SIlya Biryukov   PreambleFileHash Result;
531200b3289SIlya Biryukov   Result.Size = Buffer->getBufferSize();
532200b3289SIlya Biryukov   Result.ModTime = 0;
533200b3289SIlya Biryukov 
534200b3289SIlya Biryukov   llvm::MD5 MD5Ctx;
535200b3289SIlya Biryukov   MD5Ctx.update(Buffer->getBuffer().data());
536200b3289SIlya Biryukov   MD5Ctx.final(Result.MD5);
537200b3289SIlya Biryukov 
538200b3289SIlya Biryukov   return Result;
539200b3289SIlya Biryukov }
540200b3289SIlya Biryukov 
541200b3289SIlya Biryukov void PreambleCallbacks::AfterExecute(CompilerInstance &CI) {}
542200b3289SIlya Biryukov void PreambleCallbacks::AfterPCHEmitted(ASTWriter &Writer) {}
543200b3289SIlya Biryukov void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG) {}
544200b3289SIlya Biryukov void PreambleCallbacks::HandleMacroDefined(const Token &MacroNameTok,
545200b3289SIlya Biryukov                                            const MacroDirective *MD) {}
546200b3289SIlya Biryukov 
547200b3289SIlya Biryukov std::error_code clang::make_error_code(BuildPreambleError Error) {
548200b3289SIlya Biryukov   return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory());
549200b3289SIlya Biryukov }
550200b3289SIlya Biryukov 
551200b3289SIlya Biryukov const char *BuildPreambleErrorCategory::name() const noexcept {
552200b3289SIlya Biryukov   return "build-preamble.error";
553200b3289SIlya Biryukov }
554200b3289SIlya Biryukov 
555200b3289SIlya Biryukov std::string BuildPreambleErrorCategory::message(int condition) const {
556200b3289SIlya Biryukov   switch (static_cast<BuildPreambleError>(condition)) {
557200b3289SIlya Biryukov   case BuildPreambleError::PreambleIsEmpty:
558200b3289SIlya Biryukov     return "Preamble is empty";
559200b3289SIlya Biryukov   case BuildPreambleError::CouldntCreateTempFile:
560200b3289SIlya Biryukov     return "Could not create temporary file for PCH";
561200b3289SIlya Biryukov   case BuildPreambleError::CouldntCreateTargetInfo:
562200b3289SIlya Biryukov     return "CreateTargetInfo() return null";
563200b3289SIlya Biryukov   case BuildPreambleError::CouldntCreateVFSOverlay:
564200b3289SIlya Biryukov     return "Could not create VFS Overlay";
565200b3289SIlya Biryukov   case BuildPreambleError::BeginSourceFileFailed:
566200b3289SIlya Biryukov     return "BeginSourceFile() return an error";
567200b3289SIlya Biryukov   case BuildPreambleError::CouldntEmitPCH:
568200b3289SIlya Biryukov     return "Could not emit PCH";
569200b3289SIlya Biryukov   }
570200b3289SIlya Biryukov   llvm_unreachable("unexpected BuildPreambleError");
571200b3289SIlya Biryukov }
572