xref: /freebsd/contrib/llvm-project/clang/lib/Frontend/PrecompiledPreamble.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Helper class to build precompiled preamble.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "clang/Frontend/PrecompiledPreamble.h"
145ffd83dbSDimitry Andric #include "clang/Basic/FileManager.h"
15a7dea167SDimitry Andric #include "clang/Basic/LangStandard.h"
160b57cec5SDimitry Andric #include "clang/Frontend/CompilerInstance.h"
170b57cec5SDimitry Andric #include "clang/Frontend/CompilerInvocation.h"
180b57cec5SDimitry Andric #include "clang/Frontend/FrontendActions.h"
190b57cec5SDimitry Andric #include "clang/Frontend/FrontendOptions.h"
205ffd83dbSDimitry Andric #include "clang/Lex/HeaderSearch.h"
210b57cec5SDimitry Andric #include "clang/Lex/Lexer.h"
220b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
230b57cec5SDimitry Andric #include "clang/Lex/PreprocessorOptions.h"
240b57cec5SDimitry Andric #include "clang/Serialization/ASTWriter.h"
255ffd83dbSDimitry Andric #include "llvm/ADT/SmallString.h"
260b57cec5SDimitry Andric #include "llvm/ADT/StringSet.h"
275ffd83dbSDimitry Andric #include "llvm/ADT/iterator_range.h"
280b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
290b57cec5SDimitry Andric #include "llvm/Support/CrashRecoveryContext.h"
300b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
31*0fca6ea1SDimitry Andric #include "llvm/Support/ManagedStatic.h"
325ffd83dbSDimitry Andric #include "llvm/Support/Path.h"
330b57cec5SDimitry Andric #include "llvm/Support/Process.h"
340b57cec5SDimitry Andric #include "llvm/Support/VirtualFileSystem.h"
350b57cec5SDimitry Andric #include <limits>
36a7dea167SDimitry Andric #include <mutex>
370b57cec5SDimitry Andric #include <utility>
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric using namespace clang;
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric namespace {
420b57cec5SDimitry Andric 
getInMemoryPreamblePath()430b57cec5SDimitry Andric StringRef getInMemoryPreamblePath() {
440b57cec5SDimitry Andric #if defined(LLVM_ON_UNIX)
450b57cec5SDimitry Andric   return "/__clang_tmp/___clang_inmemory_preamble___";
460b57cec5SDimitry Andric #elif defined(_WIN32)
470b57cec5SDimitry Andric   return "C:\\__clang_tmp\\___clang_inmemory_preamble___";
480b57cec5SDimitry Andric #else
490b57cec5SDimitry Andric #warning "Unknown platform. Defaulting to UNIX-style paths for in-memory PCHs"
500b57cec5SDimitry Andric   return "/__clang_tmp/___clang_inmemory_preamble___";
510b57cec5SDimitry Andric #endif
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric IntrusiveRefCntPtr<llvm::vfs::FileSystem>
createVFSOverlayForPreamblePCH(StringRef PCHFilename,std::unique_ptr<llvm::MemoryBuffer> PCHBuffer,IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)550b57cec5SDimitry Andric createVFSOverlayForPreamblePCH(StringRef PCHFilename,
560b57cec5SDimitry Andric                                std::unique_ptr<llvm::MemoryBuffer> PCHBuffer,
570b57cec5SDimitry Andric                                IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
580b57cec5SDimitry Andric   // We want only the PCH file from the real filesystem to be available,
590b57cec5SDimitry Andric   // so we create an in-memory VFS with just that and overlay it on top.
600b57cec5SDimitry Andric   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> PCHFS(
610b57cec5SDimitry Andric       new llvm::vfs::InMemoryFileSystem());
620b57cec5SDimitry Andric   PCHFS->addFile(PCHFilename, 0, std::move(PCHBuffer));
630b57cec5SDimitry Andric   IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> Overlay(
640b57cec5SDimitry Andric       new llvm::vfs::OverlayFileSystem(VFS));
650b57cec5SDimitry Andric   Overlay->pushOverlay(PCHFS);
660b57cec5SDimitry Andric   return Overlay;
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric class PreambleDependencyCollector : public DependencyCollector {
700b57cec5SDimitry Andric public:
710b57cec5SDimitry Andric   // We want to collect all dependencies for correctness. Avoiding the real
720b57cec5SDimitry Andric   // system dependencies (e.g. stl from /usr/lib) would probably be a good idea,
730b57cec5SDimitry Andric   // but there is no way to distinguish between those and the ones that can be
740b57cec5SDimitry Andric   // spuriously added by '-isystem' (e.g. to suppress warnings from those
750b57cec5SDimitry Andric   // headers).
needSystemDependencies()760b57cec5SDimitry Andric   bool needSystemDependencies() override { return true; }
770b57cec5SDimitry Andric };
780b57cec5SDimitry Andric 
795ffd83dbSDimitry Andric // Collects files whose existence would invalidate the preamble.
805ffd83dbSDimitry Andric // Collecting *all* of these would make validating it too slow though, so we
815ffd83dbSDimitry Andric // just find all the candidates for 'file not found' diagnostics.
825ffd83dbSDimitry Andric //
835ffd83dbSDimitry Andric // A caveat that may be significant for generated files: we'll omit files under
845ffd83dbSDimitry Andric // search path entries whose roots don't exist when the preamble is built.
855ffd83dbSDimitry Andric // These are pruned by InitHeaderSearch and so we don't see the search path.
865ffd83dbSDimitry Andric // It would be nice to include them but we don't want to duplicate all the rest
875ffd83dbSDimitry Andric // of the InitHeaderSearch logic to reconstruct them.
885ffd83dbSDimitry Andric class MissingFileCollector : public PPCallbacks {
895ffd83dbSDimitry Andric   llvm::StringSet<> &Out;
905ffd83dbSDimitry Andric   const HeaderSearch &Search;
915ffd83dbSDimitry Andric   const SourceManager &SM;
925ffd83dbSDimitry Andric 
935ffd83dbSDimitry Andric public:
MissingFileCollector(llvm::StringSet<> & Out,const HeaderSearch & Search,const SourceManager & SM)945ffd83dbSDimitry Andric   MissingFileCollector(llvm::StringSet<> &Out, const HeaderSearch &Search,
955ffd83dbSDimitry Andric                        const SourceManager &SM)
965ffd83dbSDimitry Andric       : Out(Out), Search(Search), SM(SM) {}
975ffd83dbSDimitry Andric 
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,OptionalFileEntryRef File,StringRef SearchPath,StringRef RelativePath,const Module * SuggestedModule,bool ModuleImported,SrcMgr::CharacteristicKind FileType)985ffd83dbSDimitry Andric   void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
995ffd83dbSDimitry Andric                           StringRef FileName, bool IsAngled,
10081ad6265SDimitry Andric                           CharSourceRange FilenameRange,
101bdd1243dSDimitry Andric                           OptionalFileEntryRef File, StringRef SearchPath,
102*0fca6ea1SDimitry Andric                           StringRef RelativePath, const Module *SuggestedModule,
103*0fca6ea1SDimitry Andric                           bool ModuleImported,
1045ffd83dbSDimitry Andric                           SrcMgr::CharacteristicKind FileType) override {
105bdd1243dSDimitry Andric     // File is std::nullopt if it wasn't found.
1065ffd83dbSDimitry Andric     // (We have some false negatives if PP recovered e.g. <foo> -> "foo")
10781ad6265SDimitry Andric     if (File)
1085ffd83dbSDimitry Andric       return;
1095ffd83dbSDimitry Andric 
1105ffd83dbSDimitry Andric     // If it's a rare absolute include, we know the full path already.
1115ffd83dbSDimitry Andric     if (llvm::sys::path::is_absolute(FileName)) {
1125ffd83dbSDimitry Andric       Out.insert(FileName);
1135ffd83dbSDimitry Andric       return;
1145ffd83dbSDimitry Andric     }
1155ffd83dbSDimitry Andric 
1165ffd83dbSDimitry Andric     // Reconstruct the filenames that would satisfy this directive...
1175ffd83dbSDimitry Andric     llvm::SmallString<256> Buf;
11806c3fb27SDimitry Andric     auto NotFoundRelativeTo = [&](DirectoryEntryRef DE) {
11906c3fb27SDimitry Andric       Buf = DE.getName();
1205ffd83dbSDimitry Andric       llvm::sys::path::append(Buf, FileName);
1215ffd83dbSDimitry Andric       llvm::sys::path::remove_dots(Buf, /*remove_dot_dot=*/true);
1225ffd83dbSDimitry Andric       Out.insert(Buf);
1235ffd83dbSDimitry Andric     };
1245ffd83dbSDimitry Andric     // ...relative to the including file.
1255ffd83dbSDimitry Andric     if (!IsAngled) {
12606c3fb27SDimitry Andric       if (OptionalFileEntryRef IncludingFile =
12706c3fb27SDimitry Andric               SM.getFileEntryRefForID(SM.getFileID(IncludeTok.getLocation())))
1285ffd83dbSDimitry Andric         if (IncludingFile->getDir())
1295ffd83dbSDimitry Andric           NotFoundRelativeTo(IncludingFile->getDir());
1305ffd83dbSDimitry Andric     }
1315ffd83dbSDimitry Andric     // ...relative to the search paths.
1325ffd83dbSDimitry Andric     for (const auto &Dir : llvm::make_range(
1335ffd83dbSDimitry Andric              IsAngled ? Search.angled_dir_begin() : Search.search_dir_begin(),
1345ffd83dbSDimitry Andric              Search.search_dir_end())) {
1355ffd83dbSDimitry Andric       // No support for frameworks or header maps yet.
1365ffd83dbSDimitry Andric       if (Dir.isNormalDir())
13706c3fb27SDimitry Andric         NotFoundRelativeTo(*Dir.getDirRef());
1385ffd83dbSDimitry Andric     }
1395ffd83dbSDimitry Andric   }
1405ffd83dbSDimitry Andric };
1415ffd83dbSDimitry Andric 
1420b57cec5SDimitry Andric /// Keeps a track of files to be deleted in destructor.
1430b57cec5SDimitry Andric class TemporaryFiles {
1440b57cec5SDimitry Andric public:
1450b57cec5SDimitry Andric   // A static instance to be used by all clients.
1460b57cec5SDimitry Andric   static TemporaryFiles &getInstance();
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric private:
1490b57cec5SDimitry Andric   // Disallow constructing the class directly.
1500b57cec5SDimitry Andric   TemporaryFiles() = default;
1510b57cec5SDimitry Andric   // Disallow copy.
1520b57cec5SDimitry Andric   TemporaryFiles(const TemporaryFiles &) = delete;
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric public:
1550b57cec5SDimitry Andric   ~TemporaryFiles();
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric   /// Adds \p File to a set of tracked files.
1580b57cec5SDimitry Andric   void addFile(StringRef File);
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   /// Remove \p File from disk and from the set of tracked files.
1610b57cec5SDimitry Andric   void removeFile(StringRef File);
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric private:
164a7dea167SDimitry Andric   std::mutex Mutex;
1650b57cec5SDimitry Andric   llvm::StringSet<> Files;
1660b57cec5SDimitry Andric };
1670b57cec5SDimitry Andric 
getInstance()1680b57cec5SDimitry Andric TemporaryFiles &TemporaryFiles::getInstance() {
1690b57cec5SDimitry Andric   static TemporaryFiles Instance;
1700b57cec5SDimitry Andric   return Instance;
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric 
~TemporaryFiles()1730b57cec5SDimitry Andric TemporaryFiles::~TemporaryFiles() {
174a7dea167SDimitry Andric   std::lock_guard<std::mutex> Guard(Mutex);
1750b57cec5SDimitry Andric   for (const auto &File : Files)
1760b57cec5SDimitry Andric     llvm::sys::fs::remove(File.getKey());
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
addFile(StringRef File)1790b57cec5SDimitry Andric void TemporaryFiles::addFile(StringRef File) {
180a7dea167SDimitry Andric   std::lock_guard<std::mutex> Guard(Mutex);
1810b57cec5SDimitry Andric   auto IsInserted = Files.insert(File).second;
1820b57cec5SDimitry Andric   (void)IsInserted;
1830b57cec5SDimitry Andric   assert(IsInserted && "File has already been added");
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric 
removeFile(StringRef File)1860b57cec5SDimitry Andric void TemporaryFiles::removeFile(StringRef File) {
187a7dea167SDimitry Andric   std::lock_guard<std::mutex> Guard(Mutex);
1880b57cec5SDimitry Andric   auto WasPresent = Files.erase(File);
1890b57cec5SDimitry Andric   (void)WasPresent;
1900b57cec5SDimitry Andric   assert(WasPresent && "File was not tracked");
1910b57cec5SDimitry Andric   llvm::sys::fs::remove(File);
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric 
19481ad6265SDimitry Andric // A temp file that would be deleted on destructor call. If destructor is not
19581ad6265SDimitry Andric // called for any reason, the file will be deleted at static objects'
19681ad6265SDimitry Andric // destruction.
19781ad6265SDimitry Andric // An assertion will fire if two TempPCHFiles are created with the same name,
19881ad6265SDimitry Andric // so it's not intended to be used outside preamble-handling.
19981ad6265SDimitry Andric class TempPCHFile {
20081ad6265SDimitry Andric public:
20181ad6265SDimitry Andric   // A main method used to construct TempPCHFile.
create(StringRef StoragePath)20206c3fb27SDimitry Andric   static std::unique_ptr<TempPCHFile> create(StringRef StoragePath) {
20381ad6265SDimitry Andric     // FIXME: This is a hack so that we can override the preamble file during
20481ad6265SDimitry Andric     // crash-recovery testing, which is the only case where the preamble files
20581ad6265SDimitry Andric     // are not necessarily cleaned up.
20681ad6265SDimitry Andric     if (const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"))
20781ad6265SDimitry Andric       return std::unique_ptr<TempPCHFile>(new TempPCHFile(TmpFile));
20881ad6265SDimitry Andric 
20906c3fb27SDimitry Andric     llvm::SmallString<128> File;
21006c3fb27SDimitry Andric     // Using the versions of createTemporaryFile() and
21106c3fb27SDimitry Andric     // createUniqueFile() with a file descriptor guarantees
21281ad6265SDimitry Andric     // that we would never get a race condition in a multi-threaded setting
21381ad6265SDimitry Andric     // (i.e., multiple threads getting the same temporary path).
21481ad6265SDimitry Andric     int FD;
21506c3fb27SDimitry Andric     std::error_code EC;
21606c3fb27SDimitry Andric     if (StoragePath.empty())
21706c3fb27SDimitry Andric       EC = llvm::sys::fs::createTemporaryFile("preamble", "pch", FD, File);
21806c3fb27SDimitry Andric     else {
21906c3fb27SDimitry Andric       llvm::SmallString<128> TempPath = StoragePath;
22006c3fb27SDimitry Andric       // Use the same filename model as fs::createTemporaryFile().
22106c3fb27SDimitry Andric       llvm::sys::path::append(TempPath, "preamble-%%%%%%.pch");
22206c3fb27SDimitry Andric       namespace fs = llvm::sys::fs;
22306c3fb27SDimitry Andric       // Use the same owner-only file permissions as fs::createTemporaryFile().
22406c3fb27SDimitry Andric       EC = fs::createUniqueFile(TempPath, FD, File, fs::OF_None,
22506c3fb27SDimitry Andric                                 fs::owner_read | fs::owner_write);
22606c3fb27SDimitry Andric     }
22706c3fb27SDimitry Andric     if (EC)
22881ad6265SDimitry Andric       return nullptr;
22981ad6265SDimitry Andric     // We only needed to make sure the file exists, close the file right away.
23081ad6265SDimitry Andric     llvm::sys::Process::SafelyCloseFileDescriptor(FD);
23181ad6265SDimitry Andric     return std::unique_ptr<TempPCHFile>(new TempPCHFile(File.str().str()));
23281ad6265SDimitry Andric   }
23381ad6265SDimitry Andric 
23481ad6265SDimitry Andric   TempPCHFile &operator=(const TempPCHFile &) = delete;
23581ad6265SDimitry Andric   TempPCHFile(const TempPCHFile &) = delete;
~TempPCHFile()23681ad6265SDimitry Andric   ~TempPCHFile() { TemporaryFiles::getInstance().removeFile(FilePath); };
23781ad6265SDimitry Andric 
23881ad6265SDimitry Andric   /// A path where temporary file is stored.
getFilePath() const23981ad6265SDimitry Andric   llvm::StringRef getFilePath() const { return FilePath; };
24081ad6265SDimitry Andric 
24181ad6265SDimitry Andric private:
TempPCHFile(std::string FilePath)24281ad6265SDimitry Andric   TempPCHFile(std::string FilePath) : FilePath(std::move(FilePath)) {
24381ad6265SDimitry Andric     TemporaryFiles::getInstance().addFile(this->FilePath);
24481ad6265SDimitry Andric   }
24581ad6265SDimitry Andric 
24681ad6265SDimitry Andric   std::string FilePath;
24781ad6265SDimitry Andric };
24881ad6265SDimitry Andric 
2490b57cec5SDimitry Andric class PrecompilePreambleAction : public ASTFrontendAction {
2500b57cec5SDimitry Andric public:
PrecompilePreambleAction(std::shared_ptr<PCHBuffer> Buffer,bool WritePCHFile,PreambleCallbacks & Callbacks)25181ad6265SDimitry Andric   PrecompilePreambleAction(std::shared_ptr<PCHBuffer> Buffer, bool WritePCHFile,
2520b57cec5SDimitry Andric                            PreambleCallbacks &Callbacks)
25381ad6265SDimitry Andric       : Buffer(std::move(Buffer)), WritePCHFile(WritePCHFile),
25481ad6265SDimitry Andric         Callbacks(Callbacks) {}
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
2570b57cec5SDimitry Andric                                                  StringRef InFile) override;
2580b57cec5SDimitry Andric 
hasEmittedPreamblePCH() const2590b57cec5SDimitry Andric   bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
2600b57cec5SDimitry Andric 
setEmittedPreamblePCH(ASTWriter & Writer)2610b57cec5SDimitry Andric   void setEmittedPreamblePCH(ASTWriter &Writer) {
26281ad6265SDimitry Andric     if (FileOS) {
26381ad6265SDimitry Andric       *FileOS << Buffer->Data;
26481ad6265SDimitry Andric       // Make sure it hits disk now.
26581ad6265SDimitry Andric       FileOS.reset();
26681ad6265SDimitry Andric     }
26781ad6265SDimitry Andric 
2680b57cec5SDimitry Andric     this->HasEmittedPreamblePCH = true;
2690b57cec5SDimitry Andric     Callbacks.AfterPCHEmitted(Writer);
2700b57cec5SDimitry Andric   }
2710b57cec5SDimitry Andric 
BeginSourceFileAction(CompilerInstance & CI)272e8d8bef9SDimitry Andric   bool BeginSourceFileAction(CompilerInstance &CI) override {
273e8d8bef9SDimitry Andric     assert(CI.getLangOpts().CompilingPCH);
274e8d8bef9SDimitry Andric     return ASTFrontendAction::BeginSourceFileAction(CI);
275e8d8bef9SDimitry Andric   }
276e8d8bef9SDimitry Andric 
shouldEraseOutputFiles()2770b57cec5SDimitry Andric   bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
hasCodeCompletionSupport() const2780b57cec5SDimitry Andric   bool hasCodeCompletionSupport() const override { return false; }
hasASTFileSupport() const2790b57cec5SDimitry Andric   bool hasASTFileSupport() const override { return false; }
getTranslationUnitKind()2800b57cec5SDimitry Andric   TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric private:
2830b57cec5SDimitry Andric   friend class PrecompilePreambleConsumer;
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric   bool HasEmittedPreamblePCH = false;
28681ad6265SDimitry Andric   std::shared_ptr<PCHBuffer> Buffer;
28781ad6265SDimitry Andric   bool WritePCHFile; // otherwise the PCH is written into the PCHBuffer only.
28881ad6265SDimitry Andric   std::unique_ptr<llvm::raw_pwrite_stream> FileOS; // null if in-memory
2890b57cec5SDimitry Andric   PreambleCallbacks &Callbacks;
2900b57cec5SDimitry Andric };
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric class PrecompilePreambleConsumer : public PCHGenerator {
2930b57cec5SDimitry Andric public:
PrecompilePreambleConsumer(PrecompilePreambleAction & Action,Preprocessor & PP,InMemoryModuleCache & ModuleCache,StringRef isysroot,std::shared_ptr<PCHBuffer> Buffer)294*0fca6ea1SDimitry Andric   PrecompilePreambleConsumer(PrecompilePreambleAction &Action, Preprocessor &PP,
2950b57cec5SDimitry Andric                              InMemoryModuleCache &ModuleCache,
2960b57cec5SDimitry Andric                              StringRef isysroot,
29781ad6265SDimitry Andric                              std::shared_ptr<PCHBuffer> Buffer)
29881ad6265SDimitry Andric       : PCHGenerator(PP, ModuleCache, "", isysroot, std::move(Buffer),
2990b57cec5SDimitry Andric                      ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
3000b57cec5SDimitry Andric                      /*AllowASTWithErrors=*/true),
30181ad6265SDimitry Andric         Action(Action) {}
3020b57cec5SDimitry Andric 
HandleTopLevelDecl(DeclGroupRef DG)3030b57cec5SDimitry Andric   bool HandleTopLevelDecl(DeclGroupRef DG) override {
3040b57cec5SDimitry Andric     Action.Callbacks.HandleTopLevelDecl(DG);
3050b57cec5SDimitry Andric     return true;
3060b57cec5SDimitry Andric   }
3070b57cec5SDimitry Andric 
HandleTranslationUnit(ASTContext & Ctx)3080b57cec5SDimitry Andric   void HandleTranslationUnit(ASTContext &Ctx) override {
3090b57cec5SDimitry Andric     PCHGenerator::HandleTranslationUnit(Ctx);
3100b57cec5SDimitry Andric     if (!hasEmittedPCH())
3110b57cec5SDimitry Andric       return;
3120b57cec5SDimitry Andric     Action.setEmittedPreamblePCH(getWriter());
3130b57cec5SDimitry Andric   }
3140b57cec5SDimitry Andric 
shouldSkipFunctionBody(Decl * D)3155ffd83dbSDimitry Andric   bool shouldSkipFunctionBody(Decl *D) override {
3165ffd83dbSDimitry Andric     return Action.Callbacks.shouldSkipFunctionBody(D);
3175ffd83dbSDimitry Andric   }
3185ffd83dbSDimitry Andric 
3190b57cec5SDimitry Andric private:
3200b57cec5SDimitry Andric   PrecompilePreambleAction &Action;
3210b57cec5SDimitry Andric };
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)3240b57cec5SDimitry Andric PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
3250b57cec5SDimitry Andric                                             StringRef InFile) {
3260b57cec5SDimitry Andric   std::string Sysroot;
3270b57cec5SDimitry Andric   if (!GeneratePCHAction::ComputeASTConsumerArguments(CI, Sysroot))
3280b57cec5SDimitry Andric     return nullptr;
3290b57cec5SDimitry Andric 
33081ad6265SDimitry Andric   if (WritePCHFile) {
33181ad6265SDimitry Andric     std::string OutputFile; // unused
33281ad6265SDimitry Andric     FileOS = GeneratePCHAction::CreateOutputFile(CI, InFile, OutputFile);
33381ad6265SDimitry Andric     if (!FileOS)
3340b57cec5SDimitry Andric       return nullptr;
33581ad6265SDimitry Andric   }
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric   if (!CI.getFrontendOpts().RelocatablePCH)
3380b57cec5SDimitry Andric     Sysroot.clear();
3390b57cec5SDimitry Andric 
340a7dea167SDimitry Andric   return std::make_unique<PrecompilePreambleConsumer>(
34181ad6265SDimitry Andric       *this, CI.getPreprocessor(), CI.getModuleCache(), Sysroot, Buffer);
3420b57cec5SDimitry Andric }
3430b57cec5SDimitry Andric 
moveOnNoError(llvm::ErrorOr<T> Val,T & Output)3440b57cec5SDimitry Andric template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
3450b57cec5SDimitry Andric   if (!Val)
3460b57cec5SDimitry Andric     return false;
3470b57cec5SDimitry Andric   Output = std::move(*Val);
3480b57cec5SDimitry Andric   return true;
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric } // namespace
3520b57cec5SDimitry Andric 
ComputePreambleBounds(const LangOptions & LangOpts,const llvm::MemoryBufferRef & Buffer,unsigned MaxLines)3530b57cec5SDimitry Andric PreambleBounds clang::ComputePreambleBounds(const LangOptions &LangOpts,
354e8d8bef9SDimitry Andric                                             const llvm::MemoryBufferRef &Buffer,
3550b57cec5SDimitry Andric                                             unsigned MaxLines) {
356e8d8bef9SDimitry Andric   return Lexer::ComputePreamble(Buffer.getBuffer(), LangOpts, MaxLines);
3570b57cec5SDimitry Andric }
3580b57cec5SDimitry Andric 
35981ad6265SDimitry Andric class PrecompiledPreamble::PCHStorage {
36081ad6265SDimitry Andric public:
file(std::unique_ptr<TempPCHFile> File)36181ad6265SDimitry Andric   static std::unique_ptr<PCHStorage> file(std::unique_ptr<TempPCHFile> File) {
36281ad6265SDimitry Andric     assert(File);
36381ad6265SDimitry Andric     std::unique_ptr<PCHStorage> S(new PCHStorage());
36481ad6265SDimitry Andric     S->File = std::move(File);
36581ad6265SDimitry Andric     return S;
36681ad6265SDimitry Andric   }
inMemory(std::shared_ptr<PCHBuffer> Buf)36781ad6265SDimitry Andric   static std::unique_ptr<PCHStorage> inMemory(std::shared_ptr<PCHBuffer> Buf) {
36881ad6265SDimitry Andric     std::unique_ptr<PCHStorage> S(new PCHStorage());
36981ad6265SDimitry Andric     S->Memory = std::move(Buf);
37081ad6265SDimitry Andric     return S;
37181ad6265SDimitry Andric   }
37281ad6265SDimitry Andric 
37381ad6265SDimitry Andric   enum class Kind { InMemory, TempFile };
getKind() const37481ad6265SDimitry Andric   Kind getKind() const {
37581ad6265SDimitry Andric     if (Memory)
37681ad6265SDimitry Andric       return Kind::InMemory;
37781ad6265SDimitry Andric     if (File)
37881ad6265SDimitry Andric       return Kind::TempFile;
37981ad6265SDimitry Andric     llvm_unreachable("Neither Memory nor File?");
38081ad6265SDimitry Andric   }
filePath() const38181ad6265SDimitry Andric   llvm::StringRef filePath() const {
38281ad6265SDimitry Andric     assert(getKind() == Kind::TempFile);
38381ad6265SDimitry Andric     return File->getFilePath();
38481ad6265SDimitry Andric   }
memoryContents() const38581ad6265SDimitry Andric   llvm::StringRef memoryContents() const {
38681ad6265SDimitry Andric     assert(getKind() == Kind::InMemory);
38781ad6265SDimitry Andric     return StringRef(Memory->Data.data(), Memory->Data.size());
38881ad6265SDimitry Andric   }
38981ad6265SDimitry Andric 
39081ad6265SDimitry Andric   // Shrink in-memory buffers to fit.
39181ad6265SDimitry Andric   // This incurs a copy, but preambles tend to be long-lived.
39281ad6265SDimitry Andric   // Only safe to call once nothing can alias the buffer.
shrink()39381ad6265SDimitry Andric   void shrink() {
39481ad6265SDimitry Andric     if (!Memory)
39581ad6265SDimitry Andric       return;
39681ad6265SDimitry Andric     Memory->Data = decltype(Memory->Data)(Memory->Data);
39781ad6265SDimitry Andric   }
39881ad6265SDimitry Andric 
39981ad6265SDimitry Andric private:
40081ad6265SDimitry Andric   PCHStorage() = default;
40181ad6265SDimitry Andric   PCHStorage(const PCHStorage &) = delete;
40281ad6265SDimitry Andric   PCHStorage &operator=(const PCHStorage &) = delete;
40381ad6265SDimitry Andric 
40481ad6265SDimitry Andric   std::shared_ptr<PCHBuffer> Memory;
40581ad6265SDimitry Andric   std::unique_ptr<TempPCHFile> File;
40681ad6265SDimitry Andric };
40781ad6265SDimitry Andric 
40881ad6265SDimitry Andric PrecompiledPreamble::~PrecompiledPreamble() = default;
40981ad6265SDimitry Andric PrecompiledPreamble::PrecompiledPreamble(PrecompiledPreamble &&) = default;
41081ad6265SDimitry Andric PrecompiledPreamble &
41181ad6265SDimitry Andric PrecompiledPreamble::operator=(PrecompiledPreamble &&) = default;
41281ad6265SDimitry Andric 
Build(const CompilerInvocation & Invocation,const llvm::MemoryBuffer * MainFileBuffer,PreambleBounds Bounds,DiagnosticsEngine & Diagnostics,IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,std::shared_ptr<PCHContainerOperations> PCHContainerOps,bool StoreInMemory,StringRef StoragePath,PreambleCallbacks & Callbacks)4130b57cec5SDimitry Andric llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
4140b57cec5SDimitry Andric     const CompilerInvocation &Invocation,
4150b57cec5SDimitry Andric     const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
4160b57cec5SDimitry Andric     DiagnosticsEngine &Diagnostics,
4170b57cec5SDimitry Andric     IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
4180b57cec5SDimitry Andric     std::shared_ptr<PCHContainerOperations> PCHContainerOps, bool StoreInMemory,
41906c3fb27SDimitry Andric     StringRef StoragePath, PreambleCallbacks &Callbacks) {
4200b57cec5SDimitry Andric   assert(VFS && "VFS is null");
4210b57cec5SDimitry Andric 
4220b57cec5SDimitry Andric   auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
4230b57cec5SDimitry Andric   FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
4240b57cec5SDimitry Andric   PreprocessorOptions &PreprocessorOpts =
4250b57cec5SDimitry Andric       PreambleInvocation->getPreprocessorOpts();
4260b57cec5SDimitry Andric 
42781ad6265SDimitry Andric   std::shared_ptr<PCHBuffer> Buffer = std::make_shared<PCHBuffer>();
42881ad6265SDimitry Andric   std::unique_ptr<PCHStorage> Storage;
42981ad6265SDimitry Andric   if (StoreInMemory) {
43081ad6265SDimitry Andric     Storage = PCHStorage::inMemory(Buffer);
43181ad6265SDimitry Andric   } else {
4320b57cec5SDimitry Andric     // Create a temporary file for the precompiled preamble. In rare
4330b57cec5SDimitry Andric     // circumstances, this can fail.
43406c3fb27SDimitry Andric     std::unique_ptr<TempPCHFile> PreamblePCHFile =
43506c3fb27SDimitry Andric         TempPCHFile::create(StoragePath);
4360b57cec5SDimitry Andric     if (!PreamblePCHFile)
4370b57cec5SDimitry Andric       return BuildPreambleError::CouldntCreateTempFile;
43881ad6265SDimitry Andric     Storage = PCHStorage::file(std::move(PreamblePCHFile));
4390b57cec5SDimitry Andric   }
4400b57cec5SDimitry Andric 
4410b57cec5SDimitry Andric   // Save the preamble text for later; we'll need to compare against it for
4420b57cec5SDimitry Andric   // subsequent reparses.
4430b57cec5SDimitry Andric   std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(),
4440b57cec5SDimitry Andric                                   MainFileBuffer->getBufferStart() +
4450b57cec5SDimitry Andric                                       Bounds.Size);
4460b57cec5SDimitry Andric   bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine;
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric   // Tell the compiler invocation to generate a temporary precompiled header.
4490b57cec5SDimitry Andric   FrontendOpts.ProgramAction = frontend::GeneratePCH;
45081ad6265SDimitry Andric   FrontendOpts.OutputFile = std::string(
45181ad6265SDimitry Andric       StoreInMemory ? getInMemoryPreamblePath() : Storage->filePath());
4520b57cec5SDimitry Andric   PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
4530b57cec5SDimitry Andric   PreprocessorOpts.PrecompiledPreambleBytes.second = false;
4540b57cec5SDimitry Andric   // Inform preprocessor to record conditional stack when building the preamble.
4550b57cec5SDimitry Andric   PreprocessorOpts.GeneratePreamble = true;
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric   // Create the compiler instance to use for building the precompiled preamble.
4580b57cec5SDimitry Andric   std::unique_ptr<CompilerInstance> Clang(
4590b57cec5SDimitry Andric       new CompilerInstance(std::move(PCHContainerOps)));
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric   // Recover resources if we crash before exiting this method.
4620b57cec5SDimitry Andric   llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
4630b57cec5SDimitry Andric       Clang.get());
4640b57cec5SDimitry Andric 
4650b57cec5SDimitry Andric   Clang->setInvocation(std::move(PreambleInvocation));
4660b57cec5SDimitry Andric   Clang->setDiagnostics(&Diagnostics);
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric   // Create the target instance.
469fe6060f1SDimitry Andric   if (!Clang->createTarget())
4700b57cec5SDimitry Andric     return BuildPreambleError::CouldntCreateTargetInfo;
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric   if (Clang->getFrontendOpts().Inputs.size() != 1 ||
4730b57cec5SDimitry Andric       Clang->getFrontendOpts().Inputs[0].getKind().getFormat() !=
4740b57cec5SDimitry Andric           InputKind::Source ||
4750b57cec5SDimitry Andric       Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() ==
476a7dea167SDimitry Andric           Language::LLVM_IR) {
4770b57cec5SDimitry Andric     return BuildPreambleError::BadInputs;
4780b57cec5SDimitry Andric   }
4790b57cec5SDimitry Andric 
4800b57cec5SDimitry Andric   // Clear out old caches and data.
4810b57cec5SDimitry Andric   Diagnostics.Reset();
4820b57cec5SDimitry Andric   ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts());
4830b57cec5SDimitry Andric 
4840b57cec5SDimitry Andric   VFS =
4850b57cec5SDimitry Andric       createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS);
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric   // Create a file manager object to provide access to and cache the filesystem.
4880b57cec5SDimitry Andric   Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric   // Create the source manager.
4910b57cec5SDimitry Andric   Clang->setSourceManager(
4920b57cec5SDimitry Andric       new SourceManager(Diagnostics, Clang->getFileManager()));
4930b57cec5SDimitry Andric 
4940b57cec5SDimitry Andric   auto PreambleDepCollector = std::make_shared<PreambleDependencyCollector>();
4950b57cec5SDimitry Andric   Clang->addDependencyCollector(PreambleDepCollector);
4960b57cec5SDimitry Andric 
497e8d8bef9SDimitry Andric   Clang->getLangOpts().CompilingPCH = true;
498e8d8bef9SDimitry Andric 
4990b57cec5SDimitry Andric   // Remap the main source file to the preamble buffer.
5000b57cec5SDimitry Andric   StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
5010b57cec5SDimitry Andric   auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
5020b57cec5SDimitry Andric       MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
5030b57cec5SDimitry Andric   if (PreprocessorOpts.RetainRemappedFileBuffers) {
5040b57cec5SDimitry Andric     // MainFileBuffer will be deleted by unique_ptr after leaving the method.
5050b57cec5SDimitry Andric     PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get());
5060b57cec5SDimitry Andric   } else {
5070b57cec5SDimitry Andric     // In that case, remapped buffer will be deleted by CompilerInstance on
5080b57cec5SDimitry Andric     // BeginSourceFile, so we call release() to avoid double deletion.
5090b57cec5SDimitry Andric     PreprocessorOpts.addRemappedFile(MainFilePath,
5100b57cec5SDimitry Andric                                      PreambleInputBuffer.release());
5110b57cec5SDimitry Andric   }
5120b57cec5SDimitry Andric 
51381ad6265SDimitry Andric   auto Act = std::make_unique<PrecompilePreambleAction>(
51481ad6265SDimitry Andric       std::move(Buffer),
51581ad6265SDimitry Andric       /*WritePCHFile=*/Storage->getKind() == PCHStorage::Kind::TempFile,
51681ad6265SDimitry Andric       Callbacks);
5170b57cec5SDimitry Andric   if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
5180b57cec5SDimitry Andric     return BuildPreambleError::BeginSourceFileFailed;
5190b57cec5SDimitry Andric 
5204824e7fdSDimitry Andric   // Performed after BeginSourceFile to ensure Clang->Preprocessor can be
5214824e7fdSDimitry Andric   // referenced in the callback.
5224824e7fdSDimitry Andric   Callbacks.BeforeExecute(*Clang);
5234824e7fdSDimitry Andric 
5240b57cec5SDimitry Andric   std::unique_ptr<PPCallbacks> DelegatedPPCallbacks =
5250b57cec5SDimitry Andric       Callbacks.createPPCallbacks();
5260b57cec5SDimitry Andric   if (DelegatedPPCallbacks)
5270b57cec5SDimitry Andric     Clang->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks));
5280b57cec5SDimitry Andric   if (auto CommentHandler = Callbacks.getCommentHandler())
5290b57cec5SDimitry Andric     Clang->getPreprocessor().addCommentHandler(CommentHandler);
5305ffd83dbSDimitry Andric   llvm::StringSet<> MissingFiles;
5315ffd83dbSDimitry Andric   Clang->getPreprocessor().addPPCallbacks(
5325ffd83dbSDimitry Andric       std::make_unique<MissingFileCollector>(
5335ffd83dbSDimitry Andric           MissingFiles, Clang->getPreprocessor().getHeaderSearchInfo(),
5345ffd83dbSDimitry Andric           Clang->getSourceManager()));
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric   if (llvm::Error Err = Act->Execute())
5370b57cec5SDimitry Andric     return errorToErrorCode(std::move(Err));
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric   // Run the callbacks.
5400b57cec5SDimitry Andric   Callbacks.AfterExecute(*Clang);
5410b57cec5SDimitry Andric 
5420b57cec5SDimitry Andric   Act->EndSourceFile();
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric   if (!Act->hasEmittedPreamblePCH())
5450b57cec5SDimitry Andric     return BuildPreambleError::CouldntEmitPCH;
54681ad6265SDimitry Andric   Act.reset(); // Frees the PCH buffer, unless Storage keeps it in memory.
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric   // Keep track of all of the files that the source manager knows about,
5490b57cec5SDimitry Andric   // so we can verify whether they have changed or not.
5500b57cec5SDimitry Andric   llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric   SourceManager &SourceMgr = Clang->getSourceManager();
5530b57cec5SDimitry Andric   for (auto &Filename : PreambleDepCollector->getDependencies()) {
5545f757f3fSDimitry Andric     auto MaybeFile = Clang->getFileManager().getOptionalFileRef(Filename);
5555f757f3fSDimitry Andric     if (!MaybeFile ||
5565f757f3fSDimitry Andric         MaybeFile == SourceMgr.getFileEntryRefForID(SourceMgr.getMainFileID()))
5570b57cec5SDimitry Andric       continue;
5585f757f3fSDimitry Andric     auto File = *MaybeFile;
5595f757f3fSDimitry Andric     if (time_t ModTime = File.getModificationTime()) {
5605f757f3fSDimitry Andric       FilesInPreamble[File.getName()] =
5615f757f3fSDimitry Andric           PrecompiledPreamble::PreambleFileHash::createForFile(File.getSize(),
5620b57cec5SDimitry Andric                                                                ModTime);
5630b57cec5SDimitry Andric     } else {
564e8d8bef9SDimitry Andric       llvm::MemoryBufferRef Buffer =
565e8d8bef9SDimitry Andric           SourceMgr.getMemoryBufferForFileOrFake(File);
5665f757f3fSDimitry Andric       FilesInPreamble[File.getName()] =
5670b57cec5SDimitry Andric           PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
5680b57cec5SDimitry Andric     }
5690b57cec5SDimitry Andric   }
5700b57cec5SDimitry Andric 
57181ad6265SDimitry Andric   // Shrinking the storage requires extra temporary memory.
57281ad6265SDimitry Andric   // Destroying clang first reduces peak memory usage.
57381ad6265SDimitry Andric   CICleanup.unregister();
57481ad6265SDimitry Andric   Clang.reset();
57581ad6265SDimitry Andric   Storage->shrink();
5765ffd83dbSDimitry Andric   return PrecompiledPreamble(
5775ffd83dbSDimitry Andric       std::move(Storage), std::move(PreambleBytes), PreambleEndsAtStartOfLine,
5785ffd83dbSDimitry Andric       std::move(FilesInPreamble), std::move(MissingFiles));
5790b57cec5SDimitry Andric }
5800b57cec5SDimitry Andric 
getBounds() const5810b57cec5SDimitry Andric PreambleBounds PrecompiledPreamble::getBounds() const {
5820b57cec5SDimitry Andric   return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
5830b57cec5SDimitry Andric }
5840b57cec5SDimitry Andric 
getSize() const5850b57cec5SDimitry Andric std::size_t PrecompiledPreamble::getSize() const {
58681ad6265SDimitry Andric   switch (Storage->getKind()) {
5870b57cec5SDimitry Andric   case PCHStorage::Kind::InMemory:
58881ad6265SDimitry Andric     return Storage->memoryContents().size();
5890b57cec5SDimitry Andric   case PCHStorage::Kind::TempFile: {
5900b57cec5SDimitry Andric     uint64_t Result;
59181ad6265SDimitry Andric     if (llvm::sys::fs::file_size(Storage->filePath(), Result))
5920b57cec5SDimitry Andric       return 0;
5930b57cec5SDimitry Andric 
5940b57cec5SDimitry Andric     assert(Result <= std::numeric_limits<std::size_t>::max() &&
5950b57cec5SDimitry Andric            "file size did not fit into size_t");
5960b57cec5SDimitry Andric     return Result;
5970b57cec5SDimitry Andric   }
5980b57cec5SDimitry Andric   }
5990b57cec5SDimitry Andric   llvm_unreachable("Unhandled storage kind");
6000b57cec5SDimitry Andric }
6010b57cec5SDimitry Andric 
CanReuse(const CompilerInvocation & Invocation,const llvm::MemoryBufferRef & MainFileBuffer,PreambleBounds Bounds,llvm::vfs::FileSystem & VFS) const6020b57cec5SDimitry Andric bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation,
603e8d8bef9SDimitry Andric                                    const llvm::MemoryBufferRef &MainFileBuffer,
6040b57cec5SDimitry Andric                                    PreambleBounds Bounds,
605e8d8bef9SDimitry Andric                                    llvm::vfs::FileSystem &VFS) const {
6060b57cec5SDimitry Andric 
6070b57cec5SDimitry Andric   assert(
608e8d8bef9SDimitry Andric       Bounds.Size <= MainFileBuffer.getBufferSize() &&
6090b57cec5SDimitry Andric       "Buffer is too large. Bounds were calculated from a different buffer?");
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric   auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
6120b57cec5SDimitry Andric   PreprocessorOptions &PreprocessorOpts =
6130b57cec5SDimitry Andric       PreambleInvocation->getPreprocessorOpts();
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric   // We've previously computed a preamble. Check whether we have the same
6160b57cec5SDimitry Andric   // preamble now that we did before, and that there's enough space in
6170b57cec5SDimitry Andric   // the main-file buffer within the precompiled preamble to fit the
6180b57cec5SDimitry Andric   // new main file.
6190b57cec5SDimitry Andric   if (PreambleBytes.size() != Bounds.Size ||
6200b57cec5SDimitry Andric       PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
6210b57cec5SDimitry Andric       !std::equal(PreambleBytes.begin(), PreambleBytes.end(),
622e8d8bef9SDimitry Andric                   MainFileBuffer.getBuffer().begin()))
6230b57cec5SDimitry Andric     return false;
6240b57cec5SDimitry Andric   // The preamble has not changed. We may be able to re-use the precompiled
6250b57cec5SDimitry Andric   // preamble.
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric   // Check that none of the files used by the preamble have changed.
6280b57cec5SDimitry Andric   // First, make a record of those files that have been overridden via
6290b57cec5SDimitry Andric   // remapping or unsaved_files.
6300b57cec5SDimitry Andric   std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
6315ffd83dbSDimitry Andric   llvm::StringSet<> OverriddenAbsPaths; // Either by buffers or files.
6320b57cec5SDimitry Andric   for (const auto &R : PreprocessorOpts.RemappedFiles) {
6330b57cec5SDimitry Andric     llvm::vfs::Status Status;
634e8d8bef9SDimitry Andric     if (!moveOnNoError(VFS.status(R.second), Status)) {
6350b57cec5SDimitry Andric       // If we can't stat the file we're remapping to, assume that something
6360b57cec5SDimitry Andric       // horrible happened.
6370b57cec5SDimitry Andric       return false;
6380b57cec5SDimitry Andric     }
6395ffd83dbSDimitry Andric     // If a mapped file was previously missing, then it has changed.
6405ffd83dbSDimitry Andric     llvm::SmallString<128> MappedPath(R.first);
641e8d8bef9SDimitry Andric     if (!VFS.makeAbsolute(MappedPath))
6425ffd83dbSDimitry Andric       OverriddenAbsPaths.insert(MappedPath);
6430b57cec5SDimitry Andric 
6440b57cec5SDimitry Andric     OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
6450b57cec5SDimitry Andric         Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
6460b57cec5SDimitry Andric   }
6470b57cec5SDimitry Andric 
6480b57cec5SDimitry Andric   // OverridenFileBuffers tracks only the files not found in VFS.
6490b57cec5SDimitry Andric   llvm::StringMap<PreambleFileHash> OverridenFileBuffers;
6500b57cec5SDimitry Andric   for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
6510b57cec5SDimitry Andric     const PrecompiledPreamble::PreambleFileHash PreambleHash =
652e8d8bef9SDimitry Andric         PreambleFileHash::createForMemoryBuffer(RB.second->getMemBufferRef());
6530b57cec5SDimitry Andric     llvm::vfs::Status Status;
654e8d8bef9SDimitry Andric     if (moveOnNoError(VFS.status(RB.first), Status))
6550b57cec5SDimitry Andric       OverriddenFiles[Status.getUniqueID()] = PreambleHash;
6560b57cec5SDimitry Andric     else
6570b57cec5SDimitry Andric       OverridenFileBuffers[RB.first] = PreambleHash;
6585ffd83dbSDimitry Andric 
6595ffd83dbSDimitry Andric     llvm::SmallString<128> MappedPath(RB.first);
660e8d8bef9SDimitry Andric     if (!VFS.makeAbsolute(MappedPath))
6615ffd83dbSDimitry Andric       OverriddenAbsPaths.insert(MappedPath);
6620b57cec5SDimitry Andric   }
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric   // Check whether anything has changed.
6650b57cec5SDimitry Andric   for (const auto &F : FilesInPreamble) {
6660b57cec5SDimitry Andric     auto OverridenFileBuffer = OverridenFileBuffers.find(F.first());
6670b57cec5SDimitry Andric     if (OverridenFileBuffer != OverridenFileBuffers.end()) {
6680b57cec5SDimitry Andric       // The file's buffer was remapped and the file was not found in VFS.
6690b57cec5SDimitry Andric       // Check whether it matches up with the previous mapping.
6700b57cec5SDimitry Andric       if (OverridenFileBuffer->second != F.second)
6710b57cec5SDimitry Andric         return false;
6720b57cec5SDimitry Andric       continue;
6730b57cec5SDimitry Andric     }
6740b57cec5SDimitry Andric 
6750b57cec5SDimitry Andric     llvm::vfs::Status Status;
676e8d8bef9SDimitry Andric     if (!moveOnNoError(VFS.status(F.first()), Status)) {
6770b57cec5SDimitry Andric       // If the file's buffer is not remapped and we can't stat it,
6780b57cec5SDimitry Andric       // assume that something horrible happened.
6790b57cec5SDimitry Andric       return false;
6800b57cec5SDimitry Andric     }
6810b57cec5SDimitry Andric 
6820b57cec5SDimitry Andric     std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
6830b57cec5SDimitry Andric         OverriddenFiles.find(Status.getUniqueID());
6840b57cec5SDimitry Andric     if (Overridden != OverriddenFiles.end()) {
6850b57cec5SDimitry Andric       // This file was remapped; check whether the newly-mapped file
6860b57cec5SDimitry Andric       // matches up with the previous mapping.
6870b57cec5SDimitry Andric       if (Overridden->second != F.second)
6880b57cec5SDimitry Andric         return false;
6890b57cec5SDimitry Andric       continue;
6900b57cec5SDimitry Andric     }
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric     // Neither the file's buffer nor the file itself was remapped;
6930b57cec5SDimitry Andric     // check whether it has changed on disk.
6940b57cec5SDimitry Andric     if (Status.getSize() != uint64_t(F.second.Size) ||
6950b57cec5SDimitry Andric         llvm::sys::toTimeT(Status.getLastModificationTime()) !=
6960b57cec5SDimitry Andric             F.second.ModTime)
6970b57cec5SDimitry Andric       return false;
6980b57cec5SDimitry Andric   }
6995ffd83dbSDimitry Andric   for (const auto &F : MissingFiles) {
7005ffd83dbSDimitry Andric     // A missing file may be "provided" by an override buffer or file.
7015ffd83dbSDimitry Andric     if (OverriddenAbsPaths.count(F.getKey()))
7025ffd83dbSDimitry Andric       return false;
7035ffd83dbSDimitry Andric     // If a file previously recorded as missing exists as a regular file, then
7045ffd83dbSDimitry Andric     // consider the preamble out-of-date.
705e8d8bef9SDimitry Andric     if (auto Status = VFS.status(F.getKey())) {
7065ffd83dbSDimitry Andric       if (Status->isRegularFile())
7075ffd83dbSDimitry Andric         return false;
7085ffd83dbSDimitry Andric     }
7095ffd83dbSDimitry Andric   }
7100b57cec5SDimitry Andric   return true;
7110b57cec5SDimitry Andric }
7120b57cec5SDimitry Andric 
AddImplicitPreamble(CompilerInvocation & CI,IntrusiveRefCntPtr<llvm::vfs::FileSystem> & VFS,llvm::MemoryBuffer * MainFileBuffer) const7130b57cec5SDimitry Andric void PrecompiledPreamble::AddImplicitPreamble(
7140b57cec5SDimitry Andric     CompilerInvocation &CI, IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
7150b57cec5SDimitry Andric     llvm::MemoryBuffer *MainFileBuffer) const {
7160b57cec5SDimitry Andric   PreambleBounds Bounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
7170b57cec5SDimitry Andric   configurePreamble(Bounds, CI, VFS, MainFileBuffer);
7180b57cec5SDimitry Andric }
7190b57cec5SDimitry Andric 
OverridePreamble(CompilerInvocation & CI,IntrusiveRefCntPtr<llvm::vfs::FileSystem> & VFS,llvm::MemoryBuffer * MainFileBuffer) const7200b57cec5SDimitry Andric void PrecompiledPreamble::OverridePreamble(
7210b57cec5SDimitry Andric     CompilerInvocation &CI, IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
7220b57cec5SDimitry Andric     llvm::MemoryBuffer *MainFileBuffer) const {
7235f757f3fSDimitry Andric   auto Bounds = ComputePreambleBounds(CI.getLangOpts(), *MainFileBuffer, 0);
7240b57cec5SDimitry Andric   configurePreamble(Bounds, CI, VFS, MainFileBuffer);
7250b57cec5SDimitry Andric }
7260b57cec5SDimitry Andric 
PrecompiledPreamble(std::unique_ptr<PCHStorage> Storage,std::vector<char> PreambleBytes,bool PreambleEndsAtStartOfLine,llvm::StringMap<PreambleFileHash> FilesInPreamble,llvm::StringSet<> MissingFiles)7270b57cec5SDimitry Andric PrecompiledPreamble::PrecompiledPreamble(
72881ad6265SDimitry Andric     std::unique_ptr<PCHStorage> Storage, std::vector<char> PreambleBytes,
7290b57cec5SDimitry Andric     bool PreambleEndsAtStartOfLine,
7305ffd83dbSDimitry Andric     llvm::StringMap<PreambleFileHash> FilesInPreamble,
7315ffd83dbSDimitry Andric     llvm::StringSet<> MissingFiles)
7320b57cec5SDimitry Andric     : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)),
7335ffd83dbSDimitry Andric       MissingFiles(std::move(MissingFiles)),
7340b57cec5SDimitry Andric       PreambleBytes(std::move(PreambleBytes)),
7350b57cec5SDimitry Andric       PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {
73681ad6265SDimitry Andric   assert(this->Storage != nullptr);
7370b57cec5SDimitry Andric }
7380b57cec5SDimitry Andric 
7390b57cec5SDimitry Andric PrecompiledPreamble::PreambleFileHash
createForFile(off_t Size,time_t ModTime)7400b57cec5SDimitry Andric PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
7410b57cec5SDimitry Andric                                                      time_t ModTime) {
7420b57cec5SDimitry Andric   PreambleFileHash Result;
7430b57cec5SDimitry Andric   Result.Size = Size;
7440b57cec5SDimitry Andric   Result.ModTime = ModTime;
7450b57cec5SDimitry Andric   Result.MD5 = {};
7460b57cec5SDimitry Andric   return Result;
7470b57cec5SDimitry Andric }
7480b57cec5SDimitry Andric 
7490b57cec5SDimitry Andric PrecompiledPreamble::PreambleFileHash
createForMemoryBuffer(const llvm::MemoryBufferRef & Buffer)7500b57cec5SDimitry Andric PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
751e8d8bef9SDimitry Andric     const llvm::MemoryBufferRef &Buffer) {
7520b57cec5SDimitry Andric   PreambleFileHash Result;
753e8d8bef9SDimitry Andric   Result.Size = Buffer.getBufferSize();
7540b57cec5SDimitry Andric   Result.ModTime = 0;
7550b57cec5SDimitry Andric 
7560b57cec5SDimitry Andric   llvm::MD5 MD5Ctx;
757e8d8bef9SDimitry Andric   MD5Ctx.update(Buffer.getBuffer().data());
7580b57cec5SDimitry Andric   MD5Ctx.final(Result.MD5);
7590b57cec5SDimitry Andric 
7600b57cec5SDimitry Andric   return Result;
7610b57cec5SDimitry Andric }
7620b57cec5SDimitry Andric 
configurePreamble(PreambleBounds Bounds,CompilerInvocation & CI,IntrusiveRefCntPtr<llvm::vfs::FileSystem> & VFS,llvm::MemoryBuffer * MainFileBuffer) const7630b57cec5SDimitry Andric void PrecompiledPreamble::configurePreamble(
7640b57cec5SDimitry Andric     PreambleBounds Bounds, CompilerInvocation &CI,
7650b57cec5SDimitry Andric     IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
7660b57cec5SDimitry Andric     llvm::MemoryBuffer *MainFileBuffer) const {
7670b57cec5SDimitry Andric   assert(VFS);
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric   auto &PreprocessorOpts = CI.getPreprocessorOpts();
7700b57cec5SDimitry Andric 
7710b57cec5SDimitry Andric   // Remap main file to point to MainFileBuffer.
7720b57cec5SDimitry Andric   auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
7730b57cec5SDimitry Andric   PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
7740b57cec5SDimitry Andric 
7750b57cec5SDimitry Andric   // Configure ImpicitPCHInclude.
7760b57cec5SDimitry Andric   PreprocessorOpts.PrecompiledPreambleBytes.first = Bounds.Size;
7770b57cec5SDimitry Andric   PreprocessorOpts.PrecompiledPreambleBytes.second =
7780b57cec5SDimitry Andric       Bounds.PreambleEndsAtStartOfLine;
779e8d8bef9SDimitry Andric   PreprocessorOpts.DisablePCHOrModuleValidation =
780e8d8bef9SDimitry Andric       DisableValidationForModuleKind::PCH;
7810b57cec5SDimitry Andric 
78281ad6265SDimitry Andric   // Don't bother generating the long version of the predefines buffer.
78381ad6265SDimitry Andric   // The preamble is going to overwrite it anyway.
78481ad6265SDimitry Andric   PreprocessorOpts.UsePredefines = false;
78581ad6265SDimitry Andric 
78681ad6265SDimitry Andric   setupPreambleStorage(*Storage, PreprocessorOpts, VFS);
7870b57cec5SDimitry Andric }
7880b57cec5SDimitry Andric 
setupPreambleStorage(const PCHStorage & Storage,PreprocessorOptions & PreprocessorOpts,IntrusiveRefCntPtr<llvm::vfs::FileSystem> & VFS)7890b57cec5SDimitry Andric void PrecompiledPreamble::setupPreambleStorage(
7900b57cec5SDimitry Andric     const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts,
7910b57cec5SDimitry Andric     IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS) {
7920b57cec5SDimitry Andric   if (Storage.getKind() == PCHStorage::Kind::TempFile) {
79381ad6265SDimitry Andric     llvm::StringRef PCHPath = Storage.filePath();
79481ad6265SDimitry Andric     PreprocessorOpts.ImplicitPCHInclude = PCHPath.str();
7950b57cec5SDimitry Andric 
7960b57cec5SDimitry Andric     // Make sure we can access the PCH file even if we're using a VFS
7970b57cec5SDimitry Andric     IntrusiveRefCntPtr<llvm::vfs::FileSystem> RealFS =
7980b57cec5SDimitry Andric         llvm::vfs::getRealFileSystem();
7990b57cec5SDimitry Andric     if (VFS == RealFS || VFS->exists(PCHPath))
8000b57cec5SDimitry Andric       return;
8010b57cec5SDimitry Andric     auto Buf = RealFS->getBufferForFile(PCHPath);
8020b57cec5SDimitry Andric     if (!Buf) {
8030b57cec5SDimitry Andric       // We can't read the file even from RealFS, this is clearly an error,
8040b57cec5SDimitry Andric       // but we'll just leave the current VFS as is and let clang's code
8050b57cec5SDimitry Andric       // figure out what to do with missing PCH.
8060b57cec5SDimitry Andric       return;
8070b57cec5SDimitry Andric     }
8080b57cec5SDimitry Andric 
8090b57cec5SDimitry Andric     // We have a slight inconsistency here -- we're using the VFS to
8100b57cec5SDimitry Andric     // read files, but the PCH was generated in the real file system.
8110b57cec5SDimitry Andric     VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS);
8120b57cec5SDimitry Andric   } else {
8130b57cec5SDimitry Andric     assert(Storage.getKind() == PCHStorage::Kind::InMemory);
8140b57cec5SDimitry Andric     // For in-memory preamble, we have to provide a VFS overlay that makes it
8150b57cec5SDimitry Andric     // accessible.
8160b57cec5SDimitry Andric     StringRef PCHPath = getInMemoryPreamblePath();
8175ffd83dbSDimitry Andric     PreprocessorOpts.ImplicitPCHInclude = std::string(PCHPath);
8180b57cec5SDimitry Andric 
81981ad6265SDimitry Andric     auto Buf = llvm::MemoryBuffer::getMemBuffer(
82081ad6265SDimitry Andric         Storage.memoryContents(), PCHPath, /*RequiresNullTerminator=*/false);
8210b57cec5SDimitry Andric     VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS);
8220b57cec5SDimitry Andric   }
8230b57cec5SDimitry Andric }
8240b57cec5SDimitry Andric 
BeforeExecute(CompilerInstance & CI)8250b57cec5SDimitry Andric void PreambleCallbacks::BeforeExecute(CompilerInstance &CI) {}
AfterExecute(CompilerInstance & CI)8260b57cec5SDimitry Andric void PreambleCallbacks::AfterExecute(CompilerInstance &CI) {}
AfterPCHEmitted(ASTWriter & Writer)8270b57cec5SDimitry Andric void PreambleCallbacks::AfterPCHEmitted(ASTWriter &Writer) {}
HandleTopLevelDecl(DeclGroupRef DG)8280b57cec5SDimitry Andric void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG) {}
createPPCallbacks()8290b57cec5SDimitry Andric std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() {
8300b57cec5SDimitry Andric   return nullptr;
8310b57cec5SDimitry Andric }
getCommentHandler()8320b57cec5SDimitry Andric CommentHandler *PreambleCallbacks::getCommentHandler() { return nullptr; }
8330b57cec5SDimitry Andric 
8340b57cec5SDimitry Andric static llvm::ManagedStatic<BuildPreambleErrorCategory> BuildPreambleErrCategory;
8350b57cec5SDimitry Andric 
make_error_code(BuildPreambleError Error)8360b57cec5SDimitry Andric std::error_code clang::make_error_code(BuildPreambleError Error) {
8370b57cec5SDimitry Andric   return std::error_code(static_cast<int>(Error), *BuildPreambleErrCategory);
8380b57cec5SDimitry Andric }
8390b57cec5SDimitry Andric 
name() const8400b57cec5SDimitry Andric const char *BuildPreambleErrorCategory::name() const noexcept {
8410b57cec5SDimitry Andric   return "build-preamble.error";
8420b57cec5SDimitry Andric }
8430b57cec5SDimitry Andric 
message(int condition) const8440b57cec5SDimitry Andric std::string BuildPreambleErrorCategory::message(int condition) const {
8450b57cec5SDimitry Andric   switch (static_cast<BuildPreambleError>(condition)) {
8460b57cec5SDimitry Andric   case BuildPreambleError::CouldntCreateTempFile:
8470b57cec5SDimitry Andric     return "Could not create temporary file for PCH";
8480b57cec5SDimitry Andric   case BuildPreambleError::CouldntCreateTargetInfo:
8490b57cec5SDimitry Andric     return "CreateTargetInfo() return null";
8500b57cec5SDimitry Andric   case BuildPreambleError::BeginSourceFileFailed:
8510b57cec5SDimitry Andric     return "BeginSourceFile() return an error";
8520b57cec5SDimitry Andric   case BuildPreambleError::CouldntEmitPCH:
8530b57cec5SDimitry Andric     return "Could not emit PCH";
8540b57cec5SDimitry Andric   case BuildPreambleError::BadInputs:
8550b57cec5SDimitry Andric     return "Command line arguments must contain exactly one source file";
8560b57cec5SDimitry Andric   }
8570b57cec5SDimitry Andric   llvm_unreachable("unexpected BuildPreambleError");
8580b57cec5SDimitry Andric }
859