//===--- PrecompiledPreamble.h - Build precompiled preambles ----*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
// Helper class to build precompiled preamble.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_FRONTEND_PRECOMPILEDPREAMBLE_H
 
#define LLVM_CLANG_FRONTEND_PRECOMPILEDPREAMBLE_H
 
 
 
#include "clang/Lex/Lexer.h"
 
#include "clang/Lex/Preprocessor.h"
 
#include "llvm/ADT/IntrusiveRefCntPtr.h"
 
#include "llvm/ADT/StringRef.h"
 
#include "llvm/Support/MD5.h"
 
#include <cstddef>
 
#include <memory>
 
#include <system_error>
 
#include <type_traits>
 
 
 
namespace llvm {
 
class MemoryBuffer;
 
class MemoryBufferRef;
 
namespace vfs {
 
class FileSystem;
 
}
 
} // namespace llvm
 
 
 
namespace clang {
 
class CompilerInstance;
 
class CompilerInvocation;
 
class Decl;
 
class DeclGroupRef;
 
class PCHContainerOperations;
 
 
 
/// Runs lexer to compute suggested preamble bounds.
 
PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts,
 
                                     const llvm::MemoryBufferRef &Buffer,
 
                                     unsigned MaxLines);
 
 
 
class PreambleCallbacks;
 
 
 
/// A class holding a PCH and all information to check whether it is valid to
 
/// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and
 
/// CanReusePreamble + AddImplicitPreamble to make use of it.
 
class PrecompiledPreamble {
 
  class PCHStorage;
 
  struct PreambleFileHash;
 
 
 
public:
 
  /// Try to build PrecompiledPreamble for \p Invocation. See
 
  /// BuildPreambleError for possible error codes.
 
  ///
 
  /// \param Invocation Original CompilerInvocation with options to compile the
 
  /// file.
 
  ///
 
  /// \param MainFileBuffer Buffer with the contents of the main file.
 
  ///
 
  /// \param Bounds Bounds of the preamble, result of calling
 
  /// ComputePreambleBounds.
 
  ///
 
  /// \param Diagnostics Diagnostics engine to be used while building the
 
  /// preamble.
 
  ///
 
  /// \param VFS An instance of vfs::FileSystem to be used for file
 
  /// accesses.
 
  ///
 
  /// \param PCHContainerOps An instance of PCHContainerOperations.
 
  ///
 
  /// \param StoreInMemory Store PCH in memory. If false, PCH will be stored in
 
  /// a temporary file.
 
  ///
 
  /// \param Callbacks A set of callbacks to be executed when building
 
  /// the preamble.
 
  static llvm::ErrorOr<PrecompiledPreamble>
 
  Build(const CompilerInvocation &Invocation,
 
        const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
 
        DiagnosticsEngine &Diagnostics,
 
        IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
 
        std::shared_ptr<PCHContainerOperations> PCHContainerOps,
 
        bool StoreInMemory, PreambleCallbacks &Callbacks);
 
 
 
  PrecompiledPreamble(PrecompiledPreamble &&);
 
  PrecompiledPreamble &operator=(PrecompiledPreamble &&);
 
  ~PrecompiledPreamble();
 
 
 
  /// PreambleBounds used to build the preamble.
 
  PreambleBounds getBounds() const;
 
 
 
  /// Returns the size, in bytes, that preamble takes on disk or in memory.
 
  /// For on-disk preambles returns 0 if filesystem operations fail. Intended to
 
  /// be used for logging and debugging purposes only.
 
  std::size_t getSize() const;
 
 
 
  /// Returned string is not null-terminated.
 
  llvm::StringRef getContents() const {
 
    return {PreambleBytes.data(), PreambleBytes.size()};
 
  }
 
 
 
  /// Check whether PrecompiledPreamble can be reused for the new contents(\p
 
  /// MainFileBuffer) of the main file.
 
  bool CanReuse(const CompilerInvocation &Invocation,
 
                const llvm::MemoryBufferRef &MainFileBuffer,
 
                PreambleBounds Bounds, llvm::vfs::FileSystem &VFS) const;
 
 
 
  /// Changes options inside \p CI to use PCH from this preamble. Also remaps
 
  /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble
 
  /// is accessible.
 
  /// Requires that CanReuse() is true.
 
  /// For in-memory preambles, PrecompiledPreamble instance continues to own the
 
  /// MemoryBuffer with the Preamble after this method returns. The caller is
 
  /// responsible for making sure the PrecompiledPreamble instance outlives the
 
  /// compiler run and the AST that will be using the PCH.
 
  void AddImplicitPreamble(CompilerInvocation &CI,
 
                           IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
 
                           llvm::MemoryBuffer *MainFileBuffer) const;
 
 
 
  /// Configure \p CI to use this preamble.
 
  /// Like AddImplicitPreamble, but doesn't assume CanReuse() is true.
 
  /// If this preamble does not match the file, it may parse differently.
 
  void OverridePreamble(CompilerInvocation &CI,
 
                        IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
 
                        llvm::MemoryBuffer *MainFileBuffer) const;
 
 
 
private:
 
  PrecompiledPreamble(std::unique_ptr<PCHStorage> Storage,
 
                      std::vector<char> PreambleBytes,
 
                      bool PreambleEndsAtStartOfLine,
 
                      llvm::StringMap<PreambleFileHash> FilesInPreamble,
 
                      llvm::StringSet<> MissingFiles);
 
 
 
  /// Data used to determine if a file used in the preamble has been changed.
 
  struct PreambleFileHash {
 
    /// All files have size set.
 
    off_t Size = 0;
 
 
 
    /// Modification time is set for files that are on disk.  For memory
 
    /// buffers it is zero.
 
    time_t ModTime = 0;
 
 
 
    /// Memory buffers have MD5 instead of modification time.  We don't
 
    /// compute MD5 for on-disk files because we hope that modification time is
 
    /// enough to tell if the file was changed.
 
    llvm::MD5::MD5Result MD5 = {};
 
 
 
    static PreambleFileHash createForFile(off_t Size, time_t ModTime);
 
    static PreambleFileHash
 
    createForMemoryBuffer(const llvm::MemoryBufferRef &Buffer);
 
 
 
    friend bool operator==(const PreambleFileHash &LHS,
 
                           const PreambleFileHash &RHS) {
 
      return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
 
             LHS.MD5 == RHS.MD5;
 
    }
 
    friend bool operator!=(const PreambleFileHash &LHS,
 
                           const PreambleFileHash &RHS) {
 
      return !(LHS == RHS);
 
    }
 
  };
 
 
 
  /// Helper function to set up PCH for the preamble into \p CI and \p VFS to
 
  /// with the specified \p Bounds.
 
  void configurePreamble(PreambleBounds Bounds, CompilerInvocation &CI,
 
                         IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
 
                         llvm::MemoryBuffer *MainFileBuffer) const;
 
 
 
  /// Sets up the PreprocessorOptions and changes VFS, so that PCH stored in \p
 
  /// Storage is accessible to clang. This method is an implementation detail of
 
  /// AddImplicitPreamble.
 
  static void
 
  setupPreambleStorage(const PCHStorage &Storage,
 
                       PreprocessorOptions &PreprocessorOpts,
 
                       IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS);
 
 
 
  /// Manages the memory buffer or temporary file that stores the PCH.
 
  std::unique_ptr<PCHStorage> Storage;
 
  /// Keeps track of the files that were used when computing the
 
  /// preamble, with both their buffer size and their modification time.
 
  ///
 
  /// If any of the files have changed from one compile to the next,
 
  /// the preamble must be thrown away.
 
  llvm::StringMap<PreambleFileHash> FilesInPreamble;
 
  /// Files that were not found during preamble building. If any of these now
 
  /// exist then the preamble should not be reused.
 
  ///
 
  /// Storing *all* the missing files that could invalidate the preamble would
 
  /// make it too expensive to revalidate (when the include path has many
 
  /// entries, each #include will miss half of them on average).
 
  /// Instead, we track only files that could have satisfied an #include that
 
  /// was ultimately not found.
 
  llvm::StringSet<> MissingFiles;
 
  /// The contents of the file that was used to precompile the preamble. Only
 
  /// contains first PreambleBounds::Size bytes. Used to compare if the relevant
 
  /// part of the file has not changed, so that preamble can be reused.
 
  std::vector<char> PreambleBytes;
 
  /// See PreambleBounds::PreambleEndsAtStartOfLine
 
  bool PreambleEndsAtStartOfLine;
 
};
 
 
 
/// A set of callbacks to gather useful information while building a preamble.
 
class PreambleCallbacks {
 
public:
 
  virtual ~PreambleCallbacks() = default;
 
 
 
  /// Called before FrontendAction::Execute.
 
  /// Can be used to store references to various CompilerInstance fields
 
  /// (e.g. SourceManager) that may be interesting to the consumers of other
 
  /// callbacks.
 
  virtual void BeforeExecute(CompilerInstance &CI);
 
  /// Called after FrontendAction::Execute(), but before
 
  /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of
 
  /// various CompilerInstance fields before they are destroyed.
 
  virtual void AfterExecute(CompilerInstance &CI);
 
  /// Called after PCH has been emitted. \p Writer may be used to retrieve
 
  /// information about AST, serialized in PCH.
 
  virtual void AfterPCHEmitted(ASTWriter &Writer);
 
  /// Called for each TopLevelDecl.
 
  /// NOTE: To allow more flexibility a custom ASTConsumer could probably be
 
  /// used instead, but having only this method allows a simpler API.
 
  virtual void HandleTopLevelDecl(DeclGroupRef DG);
 
  /// Creates wrapper class for PPCallbacks so we can also process information
 
  /// about includes that are inside of a preamble. Called after BeforeExecute.
 
  virtual std::unique_ptr<PPCallbacks> createPPCallbacks();
 
  /// The returned CommentHandler will be added to the preprocessor if not null.
 
  virtual CommentHandler *getCommentHandler();
 
  /// Determines which function bodies are parsed, by default skips everything.
 
  /// Only used if FrontendOpts::SkipFunctionBodies is true.
 
  /// See ASTConsumer::shouldSkipFunctionBody.
 
  virtual bool shouldSkipFunctionBody(Decl *D) { return true; }
 
};
 
 
 
enum class BuildPreambleError {
 
  CouldntCreateTempFile = 1,
 
  CouldntCreateTargetInfo,
 
  BeginSourceFileFailed,
 
  CouldntEmitPCH,
 
  BadInputs
 
};
 
 
 
class BuildPreambleErrorCategory final : public std::error_category {
 
public:
 
  const char *name() const noexcept override;
 
  std::string message(int condition) const override;
 
};
 
 
 
std::error_code make_error_code(BuildPreambleError Error);
 
} // namespace clang
 
 
 
namespace std {
 
template <>
 
struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
 
} // namespace std
 
 
 
#endif