blob: 7716e2b3890170d25c56512ebaa21924505db264 [file] [log] [blame]
//===-- CompilerInstance.h - Clang Compiler Instance ------------*- C++ -*-===//
// The LLVM Compiler Infrastructure
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/PCHContainerOperations.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/ModuleLoader.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
#include <cassert>
#include <list>
#include <memory>
#include <string>
#include <utility>
namespace llvm {
class raw_fd_ostream;
class Timer;
class TimerGroup;
namespace clang {
class ASTContext;
class ASTReader;
class CodeCompleteConsumer;
class DiagnosticsEngine;
class DiagnosticConsumer;
class ExternalASTSource;
class FileEntry;
class FileManager;
class FrontendAction;
class Module;
class Preprocessor;
class Sema;
class SourceManager;
class TargetInfo;
/// CompilerInstance - Helper class for managing a single instance of the Clang
/// compiler.
/// The CompilerInstance serves two purposes:
/// (1) It manages the various objects which are necessary to run the compiler,
/// for example the preprocessor, the target information, and the AST
/// context.
/// (2) It provides utility routines for constructing and manipulating the
/// common Clang objects.
/// The compiler instance generally owns the instance of all the objects that it
/// manages. However, clients can still share objects by manually setting the
/// object and retaking ownership prior to destroying the CompilerInstance.
/// The compiler instance is intended to simplify clients, but not to lock them
/// in to the compiler instance for everything. When possible, utility functions
/// come in two forms; a short form that reuses the CompilerInstance objects,
/// and a long form that takes explicit instances of any required objects.
class CompilerInstance : public ModuleLoader {
/// The options used in this compiler instance.
std::shared_ptr<CompilerInvocation> Invocation;
/// The diagnostics engine instance.
IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
/// The target being compiled for.
IntrusiveRefCntPtr<TargetInfo> Target;
/// Auxiliary Target info.
IntrusiveRefCntPtr<TargetInfo> AuxTarget;
/// The virtual file system.
IntrusiveRefCntPtr<vfs::FileSystem> VirtualFileSystem;
/// The file manager.
IntrusiveRefCntPtr<FileManager> FileMgr;
/// The source manager.
IntrusiveRefCntPtr<SourceManager> SourceMgr;
/// The preprocessor.
std::shared_ptr<Preprocessor> PP;
/// The AST context.
IntrusiveRefCntPtr<ASTContext> Context;
/// An optional sema source that will be attached to sema.
IntrusiveRefCntPtr<ExternalSemaSource> ExternalSemaSrc;
/// The AST consumer.
std::unique_ptr<ASTConsumer> Consumer;
/// The code completion consumer.
std::unique_ptr<CodeCompleteConsumer> CompletionConsumer;
/// \brief The semantic analysis object.
std::unique_ptr<Sema> TheSema;
/// \brief The frontend timer group.
std::unique_ptr<llvm::TimerGroup> FrontendTimerGroup;
/// \brief The frontend timer.
std::unique_ptr<llvm::Timer> FrontendTimer;
/// \brief The ASTReader, if one exists.
IntrusiveRefCntPtr<ASTReader> ModuleManager;
/// \brief The module dependency collector for crashdumps
std::shared_ptr<ModuleDependencyCollector> ModuleDepCollector;
/// \brief The module provider.
std::shared_ptr<PCHContainerOperations> ThePCHContainerOperations;
/// \brief The dependency file generator.
std::unique_ptr<DependencyFileGenerator> TheDependencyFileGenerator;
std::vector<std::shared_ptr<DependencyCollector>> DependencyCollectors;
/// \brief The set of top-level modules that has already been loaded,
/// along with the module map
llvm::DenseMap<const IdentifierInfo *, Module *> KnownModules;
/// \brief The location of the module-import keyword for the last module
/// import.
SourceLocation LastModuleImportLoc;
/// \brief The result of the last module import.
ModuleLoadResult LastModuleImportResult;
/// \brief Whether we should (re)build the global module index once we
/// have finished with this translation unit.
bool BuildGlobalModuleIndex = false;
/// \brief We have a full global module index, with all modules.
bool HaveFullGlobalModuleIndex = false;
/// \brief One or more modules failed to build.
bool ModuleBuildFailed = false;
/// \brief Holds information about the output file.
/// If TempFilename is not empty we must rename it to Filename at the end.
/// TempFilename may be empty and Filename non-empty if creating the temporary
/// failed.
struct OutputFile {
std::string Filename;
std::string TempFilename;
OutputFile(std::string filename, std::string tempFilename)
: Filename(std::move(filename)), TempFilename(std::move(tempFilename)) {
/// If the output doesn't support seeking (terminal, pipe). we switch
/// the stream to a buffer_ostream. These are the buffer and the original
/// stream.
std::unique_ptr<llvm::raw_fd_ostream> NonSeekStream;
/// The list of active output files.
std::list<OutputFile> OutputFiles;
CompilerInstance(const CompilerInstance &) = delete;
void operator=(const CompilerInstance &) = delete;
explicit CompilerInstance(
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
bool BuildingModule = false);
~CompilerInstance() override;
/// @name High-Level Operations
/// {
/// ExecuteAction - Execute the provided action against the compiler's
/// CompilerInvocation object.
/// This function makes the following assumptions:
/// - The invocation options should be initialized. This function does not
/// handle the '-help' or '-version' options, clients should handle those
/// directly.
/// - The diagnostics engine should have already been created by the client.
/// - No other CompilerInstance state should have been initialized (this is
/// an unchecked error).
/// - Clients should have initialized any LLVM target features that may be
/// required.
/// - Clients should eventually call llvm_shutdown() upon the completion of
/// this routine to ensure that any managed objects are properly destroyed.
/// Note that this routine may write output to 'stderr'.
/// \param Act - The action to execute.
/// \return - True on success.
// FIXME: This function should take the stream to write any debugging /
// verbose output to as an argument.
// FIXME: Eliminate the llvm_shutdown requirement, that should either be part
// of the context or else not CompilerInstance specific.
bool ExecuteAction(FrontendAction &Act);
/// }
/// @name Compiler Invocation and Options
/// {
bool hasInvocation() const { return Invocation != nullptr; }
CompilerInvocation &getInvocation() {
assert(Invocation && "Compiler instance has no invocation!");
return *Invocation;
/// setInvocation - Replace the current invocation.
void setInvocation(std::shared_ptr<CompilerInvocation> Value);
/// \brief Indicates whether we should (re)build the global module index.
bool shouldBuildGlobalModuleIndex() const;
/// \brief Set the flag indicating whether we should (re)build the global
/// module index.
void setBuildGlobalModuleIndex(bool Build) {
BuildGlobalModuleIndex = Build;
/// }
/// @name Forwarding Methods
/// {
AnalyzerOptionsRef getAnalyzerOpts() {
return Invocation->getAnalyzerOpts();
CodeGenOptions &getCodeGenOpts() {
return Invocation->getCodeGenOpts();
const CodeGenOptions &getCodeGenOpts() const {
return Invocation->getCodeGenOpts();
DependencyOutputOptions &getDependencyOutputOpts() {
return Invocation->getDependencyOutputOpts();
const DependencyOutputOptions &getDependencyOutputOpts() const {
return Invocation->getDependencyOutputOpts();
DiagnosticOptions &getDiagnosticOpts() {
return Invocation->getDiagnosticOpts();
const DiagnosticOptions &getDiagnosticOpts() const {
return Invocation->getDiagnosticOpts();
FileSystemOptions &getFileSystemOpts() {
return Invocation->getFileSystemOpts();
const FileSystemOptions &getFileSystemOpts() const {
return Invocation->getFileSystemOpts();
FrontendOptions &getFrontendOpts() {
return Invocation->getFrontendOpts();
const FrontendOptions &getFrontendOpts() const {
return Invocation->getFrontendOpts();
HeaderSearchOptions &getHeaderSearchOpts() {
return Invocation->getHeaderSearchOpts();
const HeaderSearchOptions &getHeaderSearchOpts() const {
return Invocation->getHeaderSearchOpts();
std::shared_ptr<HeaderSearchOptions> getHeaderSearchOptsPtr() const {
return Invocation->getHeaderSearchOptsPtr();
APINotesOptions &getAPINotesOpts() {
return Invocation->getAPINotesOpts();
const APINotesOptions &getAPINotesOpts() const {
return Invocation->getAPINotesOpts();
LangOptions &getLangOpts() {
return *Invocation->getLangOpts();
const LangOptions &getLangOpts() const {
return *Invocation->getLangOpts();
PreprocessorOptions &getPreprocessorOpts() {
return Invocation->getPreprocessorOpts();
const PreprocessorOptions &getPreprocessorOpts() const {
return Invocation->getPreprocessorOpts();
PreprocessorOutputOptions &getPreprocessorOutputOpts() {
return Invocation->getPreprocessorOutputOpts();
const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
return Invocation->getPreprocessorOutputOpts();
TargetOptions &getTargetOpts() {
return Invocation->getTargetOpts();
const TargetOptions &getTargetOpts() const {
return Invocation->getTargetOpts();
/// }
/// @name Diagnostics Engine
/// {
bool hasDiagnostics() const { return Diagnostics != nullptr; }
/// Get the current diagnostics engine.
DiagnosticsEngine &getDiagnostics() const {
assert(Diagnostics && "Compiler instance has no diagnostics!");
return *Diagnostics;
/// setDiagnostics - Replace the current diagnostics engine.
void setDiagnostics(DiagnosticsEngine *Value);
DiagnosticConsumer &getDiagnosticClient() const {
assert(Diagnostics && Diagnostics->getClient() &&
"Compiler instance has no diagnostic client!");
return *Diagnostics->getClient();
/// }
/// @name Target Info
/// {
bool hasTarget() const { return Target != nullptr; }
TargetInfo &getTarget() const {
assert(Target && "Compiler instance has no target!");
return *Target;
/// Replace the current Target.
void setTarget(TargetInfo *Value);
/// }
/// @name AuxTarget Info
/// {
TargetInfo *getAuxTarget() const { return AuxTarget.get(); }
/// Replace the current AuxTarget.
void setAuxTarget(TargetInfo *Value);
/// }
/// @name Virtual File System
/// {
bool hasVirtualFileSystem() const { return VirtualFileSystem != nullptr; }
vfs::FileSystem &getVirtualFileSystem() const {
assert(hasVirtualFileSystem() &&
"Compiler instance has no virtual file system");
return *VirtualFileSystem;
/// \brief Replace the current virtual file system.
/// \note Most clients should use setFileManager, which will implicitly reset
/// the virtual file system to the one contained in the file manager.
void setVirtualFileSystem(IntrusiveRefCntPtr<vfs::FileSystem> FS) {
VirtualFileSystem = std::move(FS);
/// }
/// @name File Manager
/// {
bool hasFileManager() const { return FileMgr != nullptr; }
/// Return the current file manager to the caller.
FileManager &getFileManager() const {
assert(FileMgr && "Compiler instance has no file manager!");
return *FileMgr;
void resetAndLeakFileManager() {
/// \brief Replace the current file manager and virtual file system.
void setFileManager(FileManager *Value);
/// }
/// @name Source Manager
/// {
bool hasSourceManager() const { return SourceMgr != nullptr; }
/// Return the current source manager.
SourceManager &getSourceManager() const {
assert(SourceMgr && "Compiler instance has no source manager!");
return *SourceMgr;
void resetAndLeakSourceManager() {
/// setSourceManager - Replace the current source manager.
void setSourceManager(SourceManager *Value);
/// }
/// @name Preprocessor
/// {
bool hasPreprocessor() const { return PP != nullptr; }
/// Return the current preprocessor.
Preprocessor &getPreprocessor() const {
assert(PP && "Compiler instance has no preprocessor!");
return *PP;
std::shared_ptr<Preprocessor> getPreprocessorPtr() { return PP; }
void resetAndLeakPreprocessor() {
BuryPointer(new std::shared_ptr<Preprocessor>(PP));
/// Replace the current preprocessor.
void setPreprocessor(std::shared_ptr<Preprocessor> Value);
/// }
/// @name ASTContext
/// {
bool hasASTContext() const { return Context != nullptr; }
ASTContext &getASTContext() const {
assert(Context && "Compiler instance has no AST context!");
return *Context;
void resetAndLeakASTContext() {
/// setASTContext - Replace the current AST context.
void setASTContext(ASTContext *Value);
/// \brief Replace the current Sema; the compiler instance takes ownership
/// of S.
void setSema(Sema *S);
/// }
/// @name ASTConsumer
/// {
bool hasASTConsumer() const { return (bool)Consumer; }
ASTConsumer &getASTConsumer() const {
assert(Consumer && "Compiler instance has no AST consumer!");
return *Consumer;
/// takeASTConsumer - Remove the current AST consumer and give ownership to
/// the caller.
std::unique_ptr<ASTConsumer> takeASTConsumer() { return std::move(Consumer); }
/// setASTConsumer - Replace the current AST consumer; the compiler instance
/// takes ownership of \p Value.
void setASTConsumer(std::unique_ptr<ASTConsumer> Value);
/// }
/// @name Semantic analysis
/// {
bool hasSema() const { return (bool)TheSema; }
Sema &getSema() const {
assert(TheSema && "Compiler instance has no Sema object!");
return *TheSema;
std::unique_ptr<Sema> takeSema();
void resetAndLeakSema();
/// }
/// @name Module Management
/// {
IntrusiveRefCntPtr<ASTReader> getModuleManager() const;
void setModuleManager(IntrusiveRefCntPtr<ASTReader> Reader);
std::shared_ptr<ModuleDependencyCollector> getModuleDepCollector() const;
void setModuleDepCollector(
std::shared_ptr<ModuleDependencyCollector> Collector);
std::shared_ptr<PCHContainerOperations> getPCHContainerOperations() const {
return ThePCHContainerOperations;
/// Return the appropriate PCHContainerWriter depending on the
/// current CodeGenOptions.
const PCHContainerWriter &getPCHContainerWriter() const {
assert(Invocation && "cannot determine module format without invocation");
StringRef Format = getHeaderSearchOpts().ModuleFormat;
auto *Writer = ThePCHContainerOperations->getWriterOrNull(Format);
if (!Writer) {
if (Diagnostics)
Diagnostics->Report(diag::err_module_format_unhandled) << Format;
llvm::report_fatal_error("unknown module format");
return *Writer;
/// Return the appropriate PCHContainerReader depending on the
/// current CodeGenOptions.
const PCHContainerReader &getPCHContainerReader() const {
assert(Invocation && "cannot determine module format without invocation");
StringRef Format = getHeaderSearchOpts().ModuleFormat;
auto *Reader = ThePCHContainerOperations->getReaderOrNull(Format);
if (!Reader) {
if (Diagnostics)
Diagnostics->Report(diag::err_module_format_unhandled) << Format;
llvm::report_fatal_error("unknown module format");
return *Reader;
/// }
/// @name Code Completion
/// {
bool hasCodeCompletionConsumer() const { return (bool)CompletionConsumer; }
CodeCompleteConsumer &getCodeCompletionConsumer() const {
assert(CompletionConsumer &&
"Compiler instance has no code completion consumer!");
return *CompletionConsumer;
/// setCodeCompletionConsumer - Replace the current code completion consumer;
/// the compiler instance takes ownership of \p Value.
void setCodeCompletionConsumer(CodeCompleteConsumer *Value);
/// }
/// @name Frontend timer
/// {
bool hasFrontendTimer() const { return (bool)FrontendTimer; }
llvm::Timer &getFrontendTimer() const {
assert(FrontendTimer && "Compiler instance has no frontend timer!");
return *FrontendTimer;
/// }
/// @name Output Files
/// {
/// addOutputFile - Add an output file onto the list of tracked output files.
/// \param OutFile - The output file info.
void addOutputFile(OutputFile &&OutFile);
/// clearOutputFiles - Clear the output file list. The underlying output
/// streams must have been closed beforehand.
/// \param EraseFiles - If true, attempt to erase the files from disk.
void clearOutputFiles(bool EraseFiles);
/// }
/// @name Construction Utility Methods
/// {
/// Create the diagnostics engine using the invocation's diagnostic options
/// and replace any existing one with it.
/// Note that this routine also replaces the diagnostic client,
/// allocating one if one is not provided.
/// \param Client If non-NULL, a diagnostic client that will be
/// attached to (and, then, owned by) the DiagnosticsEngine inside this AST
/// unit.
/// \param ShouldOwnClient If Client is non-NULL, specifies whether
/// the diagnostic object should take ownership of the client.
void createDiagnostics(DiagnosticConsumer *Client = nullptr,
bool ShouldOwnClient = true);
/// Create a DiagnosticsEngine object with a the TextDiagnosticPrinter.
/// If no diagnostic client is provided, this creates a
/// DiagnosticConsumer that is owned by the returned diagnostic
/// object, if using directly the caller is responsible for
/// releasing the returned DiagnosticsEngine's client eventually.
/// \param Opts - The diagnostic options; note that the created text
/// diagnostic object contains a reference to these options.
/// \param Client If non-NULL, a diagnostic client that will be
/// attached to (and, then, owned by) the returned DiagnosticsEngine
/// object.
/// \param CodeGenOpts If non-NULL, the code gen options in use, which may be
/// used by some diagnostics printers (for logging purposes only).
/// \return The new object on success, or null on failure.
static IntrusiveRefCntPtr<DiagnosticsEngine>
createDiagnostics(DiagnosticOptions *Opts,
DiagnosticConsumer *Client = nullptr,
bool ShouldOwnClient = true,
const CodeGenOptions *CodeGenOpts = nullptr);
/// Create the file manager and replace any existing one with it.
void createFileManager();
/// Create the source manager and replace any existing one with it.
void createSourceManager(FileManager &FileMgr);
/// Create the preprocessor, using the invocation, file, and source managers,
/// and replace any existing one with it.
void createPreprocessor(TranslationUnitKind TUKind);
std::string getSpecificModuleCachePath();
/// Create the AST context.
void createASTContext();
/// Create an external AST source to read a PCH file and attach it to the AST
/// context.
void createPCHExternalASTSource(StringRef Path, bool DisablePCHValidation,
bool AllowPCHWithCompilerErrors,
void *DeserializationListener,
bool OwnDeserializationListener);
/// Create an external AST source to read a PCH file.
/// \return - The new object on success, or null on failure.
static IntrusiveRefCntPtr<ASTReader> createPCHExternalASTSource(
StringRef Path, StringRef Sysroot, bool DisablePCHValidation,
bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context,
const PCHContainerReader &PCHContainerRdr,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
void *DeserializationListener, bool OwnDeserializationListener,
bool Preamble, bool UseGlobalModuleIndex);
/// Create a code completion consumer using the invocation; note that this
/// will cause the source manager to truncate the input source file at the
/// completion point.
void createCodeCompletionConsumer();
/// Create a code completion consumer to print code completion results, at
/// \p Filename, \p Line, and \p Column, to the given output stream \p OS.
static CodeCompleteConsumer *createCodeCompletionConsumer(
Preprocessor &PP, StringRef Filename, unsigned Line, unsigned Column,
const CodeCompleteOptions &Opts, raw_ostream &OS);
/// \brief Create the Sema object to be used for parsing.
void createSema(TranslationUnitKind TUKind,
CodeCompleteConsumer *CompletionConsumer);
/// Create the frontend timer and replace any existing one with it.
void createFrontendTimer();
/// Create the default output file (from the invocation's options) and add it
/// to the list of tracked output files.
/// The files created by this function always use temporary files to write to
/// their result (that is, the data is written to a temporary file which will
/// atomically replace the target output on success).
/// \return - Null on error.
createDefaultOutputFile(bool Binary = true, StringRef BaseInput = "",
StringRef Extension = "");
/// Create a new output file and add it to the list of tracked output files,
/// optionally deriving the output path name.
/// \return - Null on error.
createOutputFile(StringRef OutputPath, bool Binary, bool RemoveFileOnSignal,
StringRef BaseInput, StringRef Extension, bool UseTemporary,
bool CreateMissingDirectories = false);
/// Create a new output file, optionally deriving the output path name.
/// If \p OutputPath is empty, then createOutputFile will derive an output
/// path location as \p BaseInput, with any suffix removed, and \p Extension
/// appended. If \p OutputPath is not stdout and \p UseTemporary
/// is true, createOutputFile will create a new temporary file that must be
/// renamed to \p OutputPath in the end.
/// \param OutputPath - If given, the path to the output file.
/// \param Error [out] - On failure, the error.
/// \param BaseInput - If \p OutputPath is empty, the input path name to use
/// for deriving the output path.
/// \param Extension - The extension to use for derived output names.
/// \param Binary - The mode to open the file in.
/// \param RemoveFileOnSignal - Whether the file should be registered with
/// llvm::sys::RemoveFileOnSignal. Note that this is not safe for
/// multithreaded use, as the underlying signal mechanism is not reentrant
/// \param UseTemporary - Create a new temporary file that must be renamed to
/// OutputPath in the end.
/// \param CreateMissingDirectories - When \p UseTemporary is true, create
/// missing directories in the output path.
/// \param ResultPathName [out] - If given, the result path name will be
/// stored here on success.
/// \param TempPathName [out] - If given, the temporary file path name
/// will be stored here on success.
createOutputFile(StringRef OutputPath, std::error_code &Error, bool Binary,
bool RemoveFileOnSignal, StringRef BaseInput,
StringRef Extension, bool UseTemporary,
bool CreateMissingDirectories, std::string *ResultPathName,
std::string *TempPathName);
std::unique_ptr<raw_pwrite_stream> createNullOutputFile();
/// }
/// @name Initialization Utility Methods
/// {
/// InitializeSourceManager - Initialize the source manager to set InputFile
/// as the main file.
/// \return True on success.
bool InitializeSourceManager(const FrontendInputFile &Input);
/// InitializeSourceManager - Initialize the source manager to set InputFile
/// as the main file.
/// \return True on success.
static bool InitializeSourceManager(const FrontendInputFile &Input,
DiagnosticsEngine &Diags,
FileManager &FileMgr,
SourceManager &SourceMgr,
HeaderSearch *HS,
DependencyOutputOptions &DepOpts,
const FrontendOptions &Opts);
/// }
// Create module manager.
void createModuleManager();
bool loadModuleFile(StringRef FileName);
ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) override;
void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc) override;
bool hadModuleLoaderFatalFailure() const {
return ModuleLoader::HadFatalFailure;
GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override;
bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override;
void addDependencyCollector(std::shared_ptr<DependencyCollector> Listener) {
void setExternalSemaSource(IntrusiveRefCntPtr<ExternalSemaSource> ESS);
} // end namespace clang