//===--- SerializedModuleLoader.h - Import Swift modules --------*- 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 // //===----------------------------------------------------------------------===// #ifndef SWIFT_SERIALIZATION_MODULELOADER_H #define SWIFT_SERIALIZATION_MODULELOADER_H #include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "llvm/Support/MemoryBuffer.h" namespace swift { class ModuleFile; namespace file_types { enum ID : uint8_t; } /// Spceifies how to load modules when both a module interface and serialized /// AST are present, or whether to disallow one format or the other altogether. enum class ModuleLoadingMode { PreferInterface, PreferSerialized, OnlyInterface, OnlySerialized }; /// Helper type used to pass and compute the sets of related filenames used by /// \c SerializedModuleLoader subclasses. struct SerializedModuleBaseName { /// The base filename, wtihout any extension. SmallString<256> baseName; /// Creates a \c SerializedModuleBaseName. SerializedModuleBaseName(StringRef baseName) : baseName(baseName) { } /// Creates a \c SerializedModuleBaseName by contextualizing an existing one /// with a \c parentDir. SerializedModuleBaseName(StringRef parentDir, const SerializedModuleBaseName &name); /// Gets the filename with a particular extension appended to it. std::string getName(file_types::ID fileTy) const; }; /// Common functionality shared between \c SerializedModuleLoader, /// \c ModuleInterfaceLoader and \c MemoryBufferSerializedModuleLoader. class SerializedModuleLoaderBase : public ModuleLoader { /// A { module, generation # } pair. using LoadedModulePair = std::pair, unsigned>; std::vector LoadedModuleFiles; SmallVector, 2> OrphanedMemoryBuffers; protected: ASTContext &Ctx; ModuleLoadingMode LoadMode; bool IgnoreSwiftSourceInfoFile; SerializedModuleLoaderBase(ASTContext &ctx, DependencyTracker *tracker, ModuleLoadingMode LoadMode, bool IgnoreSwiftSourceInfoFile); void collectVisibleTopLevelModuleNamesImpl(SmallVectorImpl &names, StringRef extension) const; using AccessPathElem = Located; bool findModule(AccessPathElem moduleID, SmallVectorImpl *moduleInterfacePath, std::unique_ptr *moduleBuffer, std::unique_ptr *moduleDocBuffer, std::unique_ptr *moduleSourceInfoBuffer, bool &isFramework, bool &isSystemModule); /// Attempts to search the provided directory for a loadable serialized /// .swiftmodule with the provided `ModuleFilename`. Subclasses must /// override this method to perform their custom module lookup behavior. /// /// If such a module could not be loaded, the subclass must return a /// `std::error_code` indicating the failure. There are two specific error /// codes that will be treated specially: /// - `errc::no_such_file_or_directory`: The module loader will stop looking /// for loadable modules and will diagnose the lookup failure. /// - `errc::not_supported`: The module loader will stop looking for loadable /// modules and will defer to the remaining module loaders to look up this /// module. virtual std::error_code findModuleFilesInDirectory( AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer) = 0; std::error_code openModuleFile( AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, std::unique_ptr *ModuleBuffer); std::error_code openModuleDocFileIfPresent( AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, std::unique_ptr *ModuleDocBuffer); std::error_code openModuleSourceInfoFileIfPresent( AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, std::unique_ptr *ModuleSourceInfoBuffer); /// If the module loader subclass knows that all options have been tried for /// loading an architecture-specific file out of a swiftmodule bundle, try /// to list the architectures that \e are present. /// /// \returns true if an error diagnostic was emitted virtual bool maybeDiagnoseTargetMismatch( SourceLoc sourceLocation, StringRef moduleName, const SerializedModuleBaseName &BaseName) { return false; } /// Determines if the provided path is a cached artifact for dependency /// tracking purposes. virtual bool isCached(StringRef DepPath) { return false; } public: virtual ~SerializedModuleLoaderBase(); SerializedModuleLoaderBase(const SerializedModuleLoaderBase &) = delete; SerializedModuleLoaderBase(SerializedModuleLoaderBase &&) = delete; SerializedModuleLoaderBase &operator=(const SerializedModuleLoaderBase &) = delete; SerializedModuleLoaderBase &operator=(SerializedModuleLoaderBase &&) = delete; /// Attempt to load a serialized AST into the given module. /// /// If the AST cannot be loaded and \p diagLoc is present, a diagnostic is /// printed. (Note that \p diagLoc is allowed to be invalid.) FileUnit *loadAST(ModuleDecl &M, Optional diagLoc, StringRef moduleInterfacePath, std::unique_ptr moduleInputBuffer, std::unique_ptr moduleDocInputBuffer, std::unique_ptr moduleSourceInfoInputBuffer, bool isFramework, bool treatAsPartialModule); /// Check whether the module with a given name can be imported without /// importing it. /// /// Note that even if this check succeeds, errors may still occur if the /// module is loaded in full. virtual bool canImportModule(Located named) override; /// Import a module with the given module path. /// /// \param importLoc The location of the 'import' keyword. /// /// \param path A sequence of (identifier, location) pairs that denote /// the dotted module name to load, e.g., AppKit.NSWindow. /// /// \returns the module referenced, if it could be loaded. Otherwise, /// emits a diagnostic and returns a FailedImportModule object. virtual ModuleDecl * loadModule(SourceLoc importLoc, ArrayRef> path) override; virtual void loadExtensions(NominalTypeDecl *nominal, unsigned previousGeneration) override; virtual void loadObjCMethods( ClassDecl *classDecl, ObjCSelector selector, bool isInstanceMethod, unsigned previousGeneration, llvm::TinyPtrVector &methods) override; virtual void verifyAllModules() override; }; /// Imports serialized Swift modules into an ASTContext. class SerializedModuleLoader : public SerializedModuleLoaderBase { SerializedModuleLoader(ASTContext &ctx, DependencyTracker *tracker, ModuleLoadingMode loadMode, bool IgnoreSwiftSourceInfo) : SerializedModuleLoaderBase(ctx, tracker, loadMode, IgnoreSwiftSourceInfo) {} std::error_code findModuleFilesInDirectory( AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer) override; bool maybeDiagnoseTargetMismatch( SourceLoc sourceLocation, StringRef moduleName, const SerializedModuleBaseName &BaseName) override; public: virtual ~SerializedModuleLoader(); /// Append visible module names to \p names. Note that names are possibly /// duplicated, and not guaranteed to be ordered in any way. void collectVisibleTopLevelModuleNames( SmallVectorImpl &names) const override; /// Create a new importer that can load serialized Swift modules /// into the given ASTContext. static std::unique_ptr create(ASTContext &ctx, DependencyTracker *tracker = nullptr, ModuleLoadingMode loadMode = ModuleLoadingMode::PreferSerialized, bool IgnoreSwiftSourceInfo = false) { return std::unique_ptr{ new SerializedModuleLoader(ctx, tracker, loadMode, IgnoreSwiftSourceInfo) }; } }; /// Imports serialized Swift modules from a MemoryBuffer into an ASTContext. /// This interface is primarily used by LLDB. class MemoryBufferSerializedModuleLoader : public SerializedModuleLoaderBase { llvm::StringMap> MemoryBuffers; MemoryBufferSerializedModuleLoader(ASTContext &ctx, DependencyTracker *tracker, ModuleLoadingMode loadMode, bool IgnoreSwiftSourceInfo) : SerializedModuleLoaderBase(ctx, tracker, loadMode, IgnoreSwiftSourceInfo) {} std::error_code findModuleFilesInDirectory( AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer) override; bool maybeDiagnoseTargetMismatch( SourceLoc sourceLocation, StringRef moduleName, const SerializedModuleBaseName &BaseName) override; public: virtual ~MemoryBufferSerializedModuleLoader(); bool canImportModule(Located named) override; ModuleDecl * loadModule(SourceLoc importLoc, ArrayRef> path) override; /// Register a memory buffer that contains the serialized module for the given /// access path. This API is intended to be used by LLDB to add swiftmodules /// discovered in the __swift_ast section of a Mach-O file (or the .swift_ast /// section of an ELF file) to the search path. /// /// FIXME: make this an actual access *path* once submodules are designed. void registerMemoryBuffer(StringRef AccessPath, std::unique_ptr input) { MemoryBuffers[AccessPath] = std::move(input); } void collectVisibleTopLevelModuleNames( SmallVectorImpl &names) const override {} /// Create a new importer that can load serialized Swift modules /// into the given ASTContext. static std::unique_ptr create(ASTContext &ctx, DependencyTracker *tracker = nullptr, ModuleLoadingMode loadMode = ModuleLoadingMode::PreferSerialized, bool IgnoreSwiftSourceInfo = false) { return std::unique_ptr{ new MemoryBufferSerializedModuleLoader(ctx, tracker, loadMode, IgnoreSwiftSourceInfo)}; } }; /// A file-unit loaded from a serialized AST file. class SerializedASTFile final : public LoadedFile { friend class SerializedModuleLoaderBase; friend class SerializedSILLoader; friend class ModuleFile; ModuleFile &File; bool IsSIB; SerializedASTFile(ModuleDecl &M, ModuleFile &file, bool isSIB = false) : LoadedFile(FileUnitKind::SerializedAST, M), File(file), IsSIB(isSIB) {} void collectLinkLibrariesFromImports(ModuleDecl::LinkLibraryCallback callback) const; public: bool isSIB() const { return IsSIB; } /// Returns the language version that was used to compile the contents of this /// file. const version::Version &getLanguageVersionBuiltWith() const; virtual bool isSystemModule() const override; virtual void lookupValue(DeclName name, NLKind lookupKind, SmallVectorImpl &results) const override; virtual StringRef getFilenameForPrivateDecl(const ValueDecl *decl) const override; virtual TypeDecl *lookupLocalType(StringRef MangledName) const override; virtual OpaqueTypeDecl * lookupOpaqueResultType(StringRef MangledName) override; virtual TypeDecl * lookupNestedType(Identifier name, const NominalTypeDecl *parent) const override; virtual OperatorDecl *lookupOperator(Identifier name, OperatorFixity fixity) const override; virtual PrecedenceGroupDecl * lookupPrecedenceGroup(Identifier name) const override; virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, VisibleDeclConsumer &consumer, NLKind lookupKind) const override; virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, VisibleDeclConsumer &consumer) const override; virtual void lookupClassMember(ModuleDecl::AccessPathTy accessPath, DeclName name, SmallVectorImpl &decls) const override; /// Find all Objective-C methods with the given selector. void lookupObjCMethods( ObjCSelector selector, SmallVectorImpl &results) const override; virtual void lookupImportedSPIGroups(const ModuleDecl *importedModule, SmallVectorImpl &spiGroups) const override; Optional getCommentForDecl(const Decl *D) const override; Optional getGroupNameForDecl(const Decl *D) const override; Optional getSourceFileNameForDecl(const Decl *D) const override; Optional getSourceOrderForDecl(const Decl *D) const override; Optional getGroupNameByUSR(StringRef USR) const override; Optional getBasicLocsForDecl(const Decl *D) const override; void collectAllGroups(std::vector &Names) const override; virtual void getTopLevelDecls(SmallVectorImpl &results) const override; virtual void getTopLevelDeclsWhereAttributesMatch( SmallVectorImpl &Results, llvm::function_ref matchAttributes) const override; virtual void getPrecedenceGroups(SmallVectorImpl &Results) const override; virtual void getLocalTypeDecls(SmallVectorImpl &results) const override; virtual void getOpaqueReturnTypeDecls(SmallVectorImpl &results) const override; virtual void getDisplayDecls(SmallVectorImpl &results) const override; virtual void getImportedModules(SmallVectorImpl &imports, ModuleDecl::ImportFilter filter) const override; virtual void collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const override; Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override; virtual StringRef getFilename() const override; virtual StringRef getModuleDefiningPath() const override; ClassDecl *getMainClass() const override; bool hasEntryPoint() const override; virtual const clang::Module *getUnderlyingClangModule() const override; virtual bool getAllGenericSignatures( SmallVectorImpl &genericSignatures) override; StringRef getTargetTriple() const; static bool classof(const FileUnit *file) { return file->getKind() == FileUnitKind::SerializedAST; } static bool classof(const DeclContext *DC) { return isa(DC) && classof(cast(DC)); } }; } // end namespace swift #endif