blob: 26ed990c98a5000716bb7f0f15814151c61e94eb [file] [log] [blame]
//===--- Frontend.h - frontend utility methods ------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file contains declarations of utility methods for parsing and
// performing semantic on modules.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_FRONTEND_H
#define SWIFT_FRONTEND_H
#include "swift/AST/DiagnosticConsumer.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/LinkLibrary.h"
#include "swift/AST/Module.h"
#include "swift/AST/SILOptions.h"
#include "swift/AST/SearchPathOptions.h"
#include "swift/Basic/DiagnosticOptions.h"
#include "swift/Basic/LangOptions.h"
#include "swift/Basic/SourceManager.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/ClangImporter/ClangImporterOptions.h"
#include "swift/Frontend/FrontendOptions.h"
#include "swift/Migrator/MigratorOptions.h"
#include "swift/Parse/CodeCompletionCallbacks.h"
#include "swift/Parse/Parser.h"
#include "swift/SIL/SILModule.h"
#include "swift/Sema/SourceLoader.h"
#include "swift/Serialization/Validation.h"
#include "swift/Subsystems.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include <memory>
namespace swift {
class SerializedModuleLoader;
/// The abstract configuration of the compiler, including:
/// - options for all stages of translation,
/// - information about the build environment,
/// - information about the job being performed, and
/// - lists of inputs.
///
/// A CompilerInvocation can be built from a frontend command line
/// using parseArgs. It can then be used to build a CompilerInstance,
/// which manages the actual compiler execution.
class CompilerInvocation {
LangOptions LangOpts;
FrontendOptions FrontendOpts;
ClangImporterOptions ClangImporterOpts;
SearchPathOptions SearchPathOpts;
DiagnosticOptions DiagnosticOpts;
MigratorOptions MigratorOpts;
SILOptions SILOpts;
IRGenOptions IRGenOpts;
llvm::MemoryBuffer *CodeCompletionBuffer = nullptr;
/// \brief Code completion offset in bytes from the beginning of the main
/// source file. Valid only if \c isCodeCompletion() == true.
unsigned CodeCompletionOffset = ~0U;
CodeCompletionCallbacksFactory *CodeCompletionFactory = nullptr;
public:
CompilerInvocation();
/// Initializes the compiler invocation for the list of arguments.
///
/// All parsing should be additive, i.e. options should not be reset to their
/// default values given the /absence/ of a flag. This is because \c parseArgs
/// may be used to modify an already partially configured invocation.
///
/// If non-empty, relative search paths are resolved relative to
/// \p workingDirectory.
///
/// \returns true if there was an error, false on success.
bool parseArgs(ArrayRef<const char *> Args, DiagnosticEngine &Diags,
StringRef workingDirectory = {});
/// Sets specific options based on the given serialized Swift binary data.
///
/// This is additive, i.e. options are not reset to their default values given
/// the /absence/ of a flag. However, flags that only have a single value may
/// (and should) be overwritten by this method.
///
/// Invoking this on more than one serialized AST is likely to result in
/// one or both of them failing to load. Please pick one AST to provide base
/// flags for the entire ASTContext and let the others succeed or fail the
/// normal way. (Some additive flags, like search paths, will be handled
/// properly during normal module loading.)
///
/// \returns Status::Valid on success, one of the Status issues on error.
serialization::Status loadFromSerializedAST(StringRef data);
/// Serialize the command line arguments for emitting them
/// to DWARF and inject SDKPath if necessary.
static void buildDWARFDebugFlags(std::string &Output,
const ArrayRef<const char*> &Args,
StringRef SDKPath,
StringRef ResourceDir);
void setTargetTriple(StringRef Triple);
StringRef getTargetTriple() const {
return LangOpts.Target.str();
}
void setClangModuleCachePath(StringRef Path) {
ClangImporterOpts.ModuleCachePath = Path.str();
}
StringRef getClangModuleCachePath() const {
return ClangImporterOpts.ModuleCachePath;
}
void setImportSearchPaths(const std::vector<std::string> &Paths) {
SearchPathOpts.ImportSearchPaths = Paths;
}
ArrayRef<std::string> getImportSearchPaths() const {
return SearchPathOpts.ImportSearchPaths;
}
void setFrameworkSearchPaths(
const std::vector<SearchPathOptions::FrameworkSearchPath> &Paths) {
SearchPathOpts.FrameworkSearchPaths = Paths;
}
ArrayRef<SearchPathOptions::FrameworkSearchPath> getFrameworkSearchPaths() const {
return SearchPathOpts.FrameworkSearchPaths;
}
void setExtraClangArgs(const std::vector<std::string> &Args) {
ClangImporterOpts.ExtraArgs = Args;
}
ArrayRef<std::string> getExtraClangArgs() const {
return ClangImporterOpts.ExtraArgs;
}
void addLinkLibrary(StringRef name, LibraryKind kind) {
IRGenOpts.LinkLibraries.push_back({name, kind});
}
ArrayRef<LinkLibrary> getLinkLibraries() const {
return IRGenOpts.LinkLibraries;
}
void setMainExecutablePath(StringRef Path);
void setRuntimeResourcePath(StringRef Path);
void setSDKPath(const std::string &Path) {
SearchPathOpts.SDKPath = Path;
}
StringRef getSDKPath() const {
return SearchPathOpts.SDKPath;
}
void setSerializedDiagnosticsPath(StringRef Path) {
FrontendOpts.SerializedDiagnosticsPath = Path;
}
StringRef getSerializedDiagnosticsPath() const {
return FrontendOpts.SerializedDiagnosticsPath;
}
LangOptions &getLangOptions() {
return LangOpts;
}
const LangOptions &getLangOptions() const {
return LangOpts;
}
FrontendOptions &getFrontendOptions() { return FrontendOpts; }
const FrontendOptions &getFrontendOptions() const { return FrontendOpts; }
ClangImporterOptions &getClangImporterOptions() { return ClangImporterOpts; }
const ClangImporterOptions &getClangImporterOptions() const {
return ClangImporterOpts;
}
SearchPathOptions &getSearchPathOptions() { return SearchPathOpts; }
const SearchPathOptions &getSearchPathOptions() const {
return SearchPathOpts;
}
DiagnosticOptions &getDiagnosticOptions() { return DiagnosticOpts; }
const DiagnosticOptions &getDiagnosticOptions() const {
return DiagnosticOpts;
}
const MigratorOptions &getMigratorOptions() const {
return MigratorOpts;
}
SILOptions &getSILOptions() { return SILOpts; }
const SILOptions &getSILOptions() const { return SILOpts; }
IRGenOptions &getIRGenOptions() { return IRGenOpts; }
const IRGenOptions &getIRGenOptions() const { return IRGenOpts; }
void setParseStdlib() {
FrontendOpts.ParseStdlib = true;
}
bool getParseStdlib() const {
return FrontendOpts.ParseStdlib;
}
void setInputKind(InputFileKind K) {
FrontendOpts.InputKind = K;
}
InputFileKind getInputKind() const {
return FrontendOpts.InputKind;
}
SourceFileKind getSourceFileKind() const;
void setModuleName(StringRef Name) {
FrontendOpts.ModuleName = Name.str();
IRGenOpts.ModuleName = Name.str();
}
StringRef getModuleName() const {
return FrontendOpts.ModuleName;
}
void addInputFilename(StringRef Filename) {
FrontendOpts.Inputs.addInputFilename(Filename);
}
/// Does not take ownership of \p Buf.
void addInputBuffer(llvm::MemoryBuffer *Buf) {
FrontendOpts.Inputs.addInputBuffer(Buf);
}
void setPrimaryInput(SelectedInput pi) {
FrontendOpts.Inputs.setPrimaryInput(pi);
}
void clearInputs() { FrontendOpts.Inputs.clearInputs(); }
StringRef getOutputFilename() const {
return FrontendOpts.getSingleOutputFilename();
}
void setCodeCompletionPoint(llvm::MemoryBuffer *Buf, unsigned Offset) {
assert(Buf);
CodeCompletionBuffer = Buf;
CodeCompletionOffset = Offset;
// We don't need typo-correction for code-completion.
// FIXME: This isn't really true, but is a performance issue.
LangOpts.TypoCorrectionLimit = 0;
}
std::pair<llvm::MemoryBuffer *, unsigned> getCodeCompletionPoint() const {
return std::make_pair(CodeCompletionBuffer, CodeCompletionOffset);
}
/// \returns true if we are doing code completion.
bool isCodeCompletion() const {
return CodeCompletionOffset != ~0U;
}
void setCodeCompletionFactory(CodeCompletionCallbacksFactory *Factory) {
CodeCompletionFactory = Factory;
}
CodeCompletionCallbacksFactory *getCodeCompletionFactory() const {
return CodeCompletionFactory;
}
/// Retrieve a module hash string that is suitable for uniquely
/// identifying the conditions under which the module was built, for use
/// in generating a cached PCH file for the bridging header.
std::string getPCHHash() const;
SourceFile::ImplicitModuleImportKind getImplicitModuleImportKind() {
if (getInputKind() == InputFileKind::IFK_SIL) {
return SourceFile::ImplicitModuleImportKind::None;
}
if (getParseStdlib()) {
return SourceFile::ImplicitModuleImportKind::Builtin;
}
return SourceFile::ImplicitModuleImportKind::Stdlib;
}
/// Performs input setup common to these tools:
/// sil-opt, sil-func-extractor, sil-llvm-gen, and sil-nm.
/// Return value includes the buffer so caller can keep it alive.
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
setUpInputForSILTool(StringRef InputFilename, StringRef ModuleNameArg,
bool alwaysSetModuleToMain,
serialization::ExtendedValidationInfo &extendedInfo);
bool hasSerializedAST() {
return FrontendOpts.InputKind == InputFileKind::IFK_Swift_Library;
}
};
/// A class which manages the state and execution of the compiler.
/// This owns the primary compiler singletons, such as the ASTContext,
/// as well as various build products such as the SILModule.
///
/// Before a CompilerInstance can be used, it must be configured by
/// calling \a setup. If successful, this will create an ASTContext
/// and set up the basic compiler invariants. Calling \a setup multiple
/// times on a single CompilerInstance is not permitted.
class CompilerInstance {
CompilerInvocation Invocation;
SourceManager SourceMgr;
DiagnosticEngine Diagnostics{SourceMgr};
std::unique_ptr<ASTContext> Context;
std::unique_ptr<SILModule> TheSILModule;
DependencyTracker *DepTracker = nullptr;
ReferencedNameTracker *NameTracker = nullptr;
ModuleDecl *MainModule = nullptr;
SerializedModuleLoader *SML = nullptr;
/// Contains buffer IDs for input source code files.
std::vector<unsigned> InputSourceCodeBufferIDs;
struct PartialModuleInputs {
std::unique_ptr<llvm::MemoryBuffer> ModuleBuffer;
std::unique_ptr<llvm::MemoryBuffer> ModuleDocBuffer;
};
/// Contains \c MemoryBuffers for partial serialized module files and
/// corresponding partial serialized module documentation files.
std::vector<PartialModuleInputs> PartialModules;
enum : unsigned { NO_SUCH_BUFFER = ~0U };
unsigned MainBufferID = NO_SUCH_BUFFER;
/// PrimaryBufferID corresponds to PrimaryInput.
unsigned PrimaryBufferID = NO_SUCH_BUFFER;
bool isWholeModuleCompilation() { return PrimaryBufferID == NO_SUCH_BUFFER; }
SourceFile *PrimarySourceFile = nullptr;
void createSILModule();
void setPrimarySourceFile(SourceFile *SF);
bool setupForFileAt(unsigned i);
public:
SourceManager &getSourceMgr() { return SourceMgr; }
DiagnosticEngine &getDiags() { return Diagnostics; }
ASTContext &getASTContext() {
return *Context;
}
bool hasASTContext() const { return Context != nullptr; }
SILOptions &getSILOptions() { return Invocation.getSILOptions(); }
const SILOptions &getSILOptions() const { return Invocation.getSILOptions(); }
void addDiagnosticConsumer(DiagnosticConsumer *DC) {
Diagnostics.addConsumer(*DC);
}
void setDependencyTracker(DependencyTracker *DT) {
assert(!Context && "must be called before setup()");
DepTracker = DT;
}
DependencyTracker *getDependencyTracker() {
return DepTracker;
}
void setReferencedNameTracker(ReferencedNameTracker *tracker) {
assert(!PrimarySourceFile && "must be called before performSema()");
NameTracker = tracker;
}
ReferencedNameTracker *getReferencedNameTracker() {
return NameTracker;
}
/// Set the SIL module for this compilation instance.
///
/// The CompilerInstance takes ownership of the given SILModule object.
void setSILModule(std::unique_ptr<SILModule> M) {
TheSILModule = std::move(M);
}
SILModule *getSILModule() {
return TheSILModule.get();
}
std::unique_ptr<SILModule> takeSILModule() {
return std::move(TheSILModule);
}
bool hasSILModule() {
return static_cast<bool>(TheSILModule);
}
ModuleDecl *getMainModule();
SerializedModuleLoader *getSerializedModuleLoader() const { return SML; }
ArrayRef<unsigned> getInputBufferIDs() const {
return InputSourceCodeBufferIDs;
}
ArrayRef<LinkLibrary> getLinkLibraries() const {
return Invocation.getLinkLibraries();
}
bool hasSourceImport() const {
return Invocation.getFrontendOptions().EnableSourceImport;
}
/// Gets the SourceFile which is the primary input for this CompilerInstance.
/// \returns the primary SourceFile, or nullptr if there is no primary input
SourceFile *getPrimarySourceFile() { return PrimarySourceFile; }
/// \brief Returns true if there was an error during setup.
bool setup(const CompilerInvocation &Invocation);
/// Parses and type-checks all input files.
void performSema();
/// Parses the input file but does no type-checking or module imports.
/// Note that this only supports parsing an invocation with a single file.
///
///
void performParseOnly(bool EvaluateConditionals = false);
/// Frees up the ASTContext and SILModule objects that this instance is
/// holding on.
void freeContextAndSIL();
private:
/// Load stdlib & return true if should continue, i.e. no error
bool loadStdlib();
ModuleDecl *importUnderlyingModule();
ModuleDecl *importBridgingHeader();
void
getImplicitlyImportedModules(SmallVectorImpl<ModuleDecl *> &importModules);
public: // for static functions in Frontend.cpp
struct ImplicitImports {
SourceFile::ImplicitModuleImportKind kind;
ModuleDecl *objCModuleUnderlyingMixedFramework;
ModuleDecl *headerModule;
SmallVector<ModuleDecl *, 4> modules;
explicit ImplicitImports(CompilerInstance &compiler);
};
private:
void createREPLFile(const ImplicitImports &implicitImports) const;
std::unique_ptr<DelayedParsingCallbacks>
computeDelayedParsingCallback(bool isPrimary);
void addMainFileToModule(const ImplicitImports &implicitImports);
void parseAndCheckTypes(const ImplicitImports &implicitImports);
void parseLibraryFile(unsigned BufferID,
const ImplicitImports &implicitImports,
PersistentParserState &PersistentState,
DelayedParsingCallbacks *PrimaryDelayedCB,
DelayedParsingCallbacks *SecondaryDelayedCB);
/// Return true if had load error
bool
parsePartialModulesAndLibraryFiles(const ImplicitImports &implicitImports,
PersistentParserState &PersistentState,
DelayedParsingCallbacks *PrimaryDelayedCB,
DelayedParsingCallbacks *SecondaryDelayedCB);
OptionSet<TypeCheckingFlags> computeTypeCheckingOptions();
void forEachFileToTypeCheck(llvm::function_ref<void(SourceFile &)> fn);
void parseAndTypeCheckMainFile(PersistentParserState &PersistentState,
DelayedParsingCallbacks *DelayedParseCB,
OptionSet<TypeCheckingFlags> TypeCheckOptions);
void finishTypeChecking(OptionSet<TypeCheckingFlags> TypeCheckOptions);
};
} // namespace swift
#endif