blob: 2871fdcadf222e697cb7e18612d5c59526ab6f88 [file] [log] [blame]
//===-- CompilerInstance.h - Flang Compiler Instance ------------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_FLANG_FRONTEND_COMPILERINSTANCE_H
#define LLVM_FLANG_FRONTEND_COMPILERINSTANCE_H
#include "flang/Frontend/CompilerInvocation.h"
#include "flang/Frontend/FrontendAction.h"
#include "flang/Frontend/PreprocessorOptions.h"
#include "flang/Parser/parsing.h"
#include "flang/Parser/provenance.h"
#include "flang/Semantics/semantics.h"
#include "llvm/Support/raw_ostream.h"
namespace Fortran::frontend {
/// Helper class for managing a single instance of the Flang compiler.
///
/// This class serves two purposes:
/// (1) It manages the various objects which are necessary to run the compiler
/// (2) It provides utility routines for constructing and manipulating the
/// common Flang 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 {
/// The options used in this compiler instance.
std::shared_ptr<CompilerInvocation> invocation_;
/// Flang file manager.
std::shared_ptr<Fortran::parser::AllSources> allSources_;
std::shared_ptr<Fortran::parser::AllCookedSources> allCookedSources_;
std::shared_ptr<Fortran::parser::Parsing> parsing_;
std::unique_ptr<Fortran::semantics::Semantics> semantics_;
/// The stream for diagnostics from Semantics
llvm::raw_ostream *semaOutputStream_ = &llvm::errs();
/// The stream for diagnostics from Semantics if owned, otherwise nullptr.
std::unique_ptr<llvm::raw_ostream> ownedSemaOutputStream_;
/// The diagnostics engine instance.
llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_;
/// Holds information about the output file.
struct OutputFile {
std::string filename_;
OutputFile(std::string inputFilename)
: filename_(std::move(inputFilename)) {}
};
/// The list of active output files.
std::list<OutputFile> outputFiles_;
/// Holds the output stream provided by the user. Normally, users of
/// CompilerInstance will call CreateOutputFile to obtain/create an output
/// stream. If they want to provide their own output stream, this field will
/// facilitate this. It is optional and will normally be just a nullptr.
std::unique_ptr<llvm::raw_pwrite_stream> outputStream_;
public:
explicit CompilerInstance();
~CompilerInstance();
/// @name Compiler Invocation
/// {
CompilerInvocation &invocation() {
assert(invocation_ && "Compiler instance has no invocation!");
return *invocation_;
};
/// Replace the current invocation.
void set_invocation(std::shared_ptr<CompilerInvocation> value);
/// }
/// @name File manager
/// {
/// Return the current allSources.
Fortran::parser::AllSources &allSources() const { return *allSources_; }
bool HasAllSources() const { return allSources_ != nullptr; }
parser::AllCookedSources &allCookedSources() {
assert(allCookedSources_ && "Compiler instance has no AllCookedSources!");
return *allCookedSources_;
};
/// }
/// @name Parser Operations
/// {
/// Return parsing to be used by Actions.
Fortran::parser::Parsing &parsing() const { return *parsing_; }
/// }
/// @name Semantic analysis
/// {
/// Replace the current stream for verbose output.
void set_semaOutputStream(llvm::raw_ostream &Value);
/// Replace the current stream for verbose output.
void set_semaOutputStream(std::unique_ptr<llvm::raw_ostream> Value);
/// Get the current stream for verbose output.
llvm::raw_ostream &semaOutputStream() { return *semaOutputStream_; }
Fortran::semantics::Semantics &semantics() { return *semantics_; }
const Fortran::semantics::Semantics &semantics() const { return *semantics_; }
void setSemantics(std::unique_ptr<Fortran::semantics::Semantics> semantics) {
semantics_ = std::move(semantics);
}
/// }
/// @name High-Level Operations
/// {
/// Execute the provided action against the compiler's
/// CompilerInvocation object.
/// \param act - The action to execute.
/// \return - True on success.
bool ExecuteAction(FrontendAction &act);
/// }
/// @name Forwarding Methods
/// {
clang::DiagnosticOptions &GetDiagnosticOpts() {
return invocation_->GetDiagnosticOpts();
}
const clang::DiagnosticOptions &GetDiagnosticOpts() const {
return invocation_->GetDiagnosticOpts();
}
FrontendOptions &frontendOpts() { return invocation_->frontendOpts(); }
const FrontendOptions &frontendOpts() const {
return invocation_->frontendOpts();
}
PreprocessorOptions &preprocessorOpts() {
return invocation_->preprocessorOpts();
}
const PreprocessorOptions &preprocessorOpts() const {
return invocation_->preprocessorOpts();
}
/// }
/// @name Diagnostics Engine
/// {
bool HasDiagnostics() const { return diagnostics_ != nullptr; }
/// Get the current diagnostics engine.
clang::DiagnosticsEngine &diagnostics() const {
assert(diagnostics_ && "Compiler instance has no diagnostics!");
return *diagnostics_;
}
clang::DiagnosticConsumer &GetDiagnosticClient() const {
assert(diagnostics_ && diagnostics_->getClient() &&
"Compiler instance has no diagnostic client!");
return *diagnostics_->getClient();
}
/// {
/// @name Output Files
/// {
/// Clear the output file list.
void ClearOutputFiles(bool eraseFiles);
/// Create the default output file (based on the invocation's options) and
/// add it to the list of tracked output files. If the name of the output
/// file is not provided, it will be derived from the input file.
///
/// \param binary The mode to open the file in.
/// \param baseInput If the invocation contains no output file name (i.e.
/// outputFile in FrontendOptions is empty), the input path
/// name to use for deriving the output path.
/// \param extension The extension to use for output names derived from
/// \p baseInput.
/// \return Null on error, ostream for the output file otherwise
std::unique_ptr<llvm::raw_pwrite_stream> CreateDefaultOutputFile(
bool binary = true, llvm::StringRef baseInput = "",
llvm::StringRef extension = "");
private:
/// Create a new output file
///
/// \param outputPath The path to the output file.
/// \param binary The mode to open the file in.
/// \return Null on error, ostream for the output file otherwise
llvm::Expected<std::unique_ptr<llvm::raw_pwrite_stream>> CreateOutputFileImpl(
llvm::StringRef outputPath, bool binary);
public:
/// }
/// @name Construction Utility Methods
/// {
/// Create a DiagnosticsEngine object
///
/// If no diagnostic client is provided, this method 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 optionally, depending on /p shouldOwnClient, owned by) the returned
/// DiagnosticsEngine object.
///
/// \return The new object on success, or null on failure.
static clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine> CreateDiagnostics(
clang::DiagnosticOptions *opts,
clang::DiagnosticConsumer *client = nullptr, bool shouldOwnClient = true);
void CreateDiagnostics(
clang::DiagnosticConsumer *client = nullptr, bool shouldOwnClient = true);
/// }
/// @name Output Stream Methods
/// {
void set_outputStream(std::unique_ptr<llvm::raw_pwrite_stream> outStream) {
outputStream_ = std::move(outStream);
}
bool IsOutputStreamNull() { return (outputStream_ == nullptr); }
// Allow the frontend compiler to write in the output stream.
void WriteOutputStream(const std::string &message) {
*outputStream_ << message;
}
};
} // end namespace Fortran::frontend
#endif // LLVM_FLANG_FRONTEND_COMPILERINSTANCE_H