//===--- ModuleLoader.h - Module Loader Interface ---------------*- 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 implements an abstract interface for loading modules. // //===----------------------------------------------------------------------===// #ifndef SWIFT_AST_MODULE_LOADER_H #define SWIFT_AST_MODULE_LOADER_H #include "swift/AST/Identifier.h" #include "swift/AST/Import.h" #include "swift/Basic/ArrayRefView.h" #include "swift/Basic/Fingerprint.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/Located.h" #include "swift/Basic/SourceLoc.h" #include "clang/Basic/FileManager.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/VersionTuple.h" #include #include namespace llvm { class FileCollectorBase; class PrefixMapper; namespace vfs { class OutputBackend; } namespace cas { class CachingOnDiskFileSystem; } } namespace clang { class DependencyCollector; namespace tooling { namespace dependencies { struct ModuleID; class DependencyScanningTool; } } } namespace swift { class AbstractFunctionDecl; struct AutoDiffConfig; class ClangImporterOptions; class ClassDecl; class FileUnit; class ModuleDecl; class ModuleDependencyInfo; struct ModuleDependencyID; class ModuleDependenciesCache; class NominalTypeDecl; class SourceFile; class TypeDecl; class CompilerInstance; enum class ModuleDependencyKind : int8_t; enum class KnownProtocolKind : uint8_t; enum class Bridgeability : unsigned { /// This context does not permit bridging at all. For example, the /// target of a C pointer. None, /// This context permits all kinds of bridging. For example, the /// imported result of a method declaration. Full }; /// Specifies which dependencies the intermodule dependency tracker records. enum class IntermoduleDepTrackingMode { /// Records both system and non-system dependencies. IncludeSystem, /// Records only non-system dependencies. ExcludeSystem, }; /// Records dependencies on files outside of the current module; /// implemented in terms of a wrapped clang::DependencyCollector. class DependencyTracker { public: /// A representation of a first-class incremental dependency known to the /// Swift compiler. struct IncrementalDependency { std::string path; Fingerprint fingerprint; IncrementalDependency(std::string Path, Fingerprint FP) : path(std::move(Path)), fingerprint(std::move(FP)) {} }; struct MacroPluginDependency { Identifier moduleName; std::string path; MacroPluginDependency(const Identifier &moduleName, const std::string &path) : moduleName(moduleName), path(path) {} }; template inline static const std::string getPath(const Dep &dep) { return dep.path; } template using PathArrayRefView = ArrayRefView; std::shared_ptr clangCollector; SmallVector incrementalDeps; llvm::StringSet<> incrementalDepsUniquer; llvm::SetVector macroPluginDeps; public: explicit DependencyTracker( IntermoduleDepTrackingMode Mode, std::shared_ptr FileCollector = {}); /// Adds a file as a dependency. /// /// The contents of \p File are taken literally, and should be appropriate /// for appearing in a list of dependencies suitable for tooling like Make. /// No path canonicalization is done. void addDependency(StringRef File, bool IsSystem); /// Adds a file as an incremental dependency. /// /// No additional canonicalization or adulteration of the file path in /// \p File is performed. void addIncrementalDependency(StringRef File, Fingerprint FP); /// Adds a macro plugin dependency. /// /// No additional canonicalization or adulteration of the file path in /// \p File is performed. void addMacroPluginDependency(StringRef File, Identifier ModuleName); /// Fetches the list of dependencies. ArrayRef getDependencies() const; /// Fetches the list of dependencies that are known to have incremental swift /// dependency information embedded inside of them. ArrayRef getIncrementalDependencies() const; /// A view of the paths of the dependencies known to have incremental swift /// dependency information embedded inside of them. PathArrayRefView getIncrementalDependencyPaths() const { return PathArrayRefView( getIncrementalDependencies()); } /// The list of macro plugin dependencies. ArrayRef getMacroPluginDependencies() const; PathArrayRefView getMacroPluginDependencyPaths() const { return PathArrayRefView( getMacroPluginDependencies()); } /// Return the underlying clang::DependencyCollector that this /// class wraps. std::shared_ptr getClangCollector(); }; struct SubCompilerInstanceInfo { StringRef CompilerVersion; CompilerInstance* Instance; StringRef Hash; ArrayRef BuildArguments; }; /// Abstract interface for a checker of module interfaces and prebuilt modules. class ModuleInterfaceChecker { public: virtual std::vector getCompiledModuleCandidatesForInterface(StringRef moduleName, StringRef interfacePath) = 0; /// Given a list of potential ready-to-use compiled modules for \p interfacePath, /// check if any one of them is up-to-date. If so, emit a forwarding module /// to the candidate binary module to \p outPath. virtual bool tryEmitForwardingModule(StringRef moduleName, StringRef interfacePath, ArrayRef candidates, llvm::vfs::OutputBackend &backend, StringRef outPath) = 0; virtual ~ModuleInterfaceChecker() = default; }; /// Abstract interface to run an action in a sub ASTContext. struct InterfaceSubContextDelegate { virtual std::error_code runInSubContext(StringRef moduleName, StringRef interfacePath, StringRef sdkPath, std::optional sysroot, StringRef outputPath, SourceLoc diagLoc, llvm::function_ref, StringRef, StringRef)> action) = 0; virtual std::error_code runInSubCompilerInstance(StringRef moduleName, StringRef interfacePath, StringRef sdkPath, std::optional sysroot, StringRef outputPath, SourceLoc diagLoc, bool silenceErrors, llvm::function_ref action) = 0; virtual ~InterfaceSubContextDelegate() = default; }; /// Abstract interface that loads named modules into the AST. class ModuleLoader { virtual void anchor(); protected: DependencyTracker * const dependencyTracker; ModuleLoader(DependencyTracker *tracker) : dependencyTracker(tracker) {} public: virtual ~ModuleLoader() = default; /// Collect visible module names. /// /// Append visible module names to \p names. Note that names are possibly /// duplicated, and not guaranteed to be ordered in any way. virtual void collectVisibleTopLevelModuleNames( SmallVectorImpl &names) const = 0; /// The kind of source for a module's version. /// /// NOTE: The order of the members is significant; they are declared in /// ascending priority order. enum class ModuleVersionSourceKind { ClangModuleTBD, SwiftBinaryModule, SwiftInterface, }; /// Represents a module version and the source it was parsed from. class ModuleVersionInfo { llvm::VersionTuple Version; std::optional SourceKind; public: /// Returns true if the version has a valid source kind. bool isValid() const { return SourceKind.has_value(); } /// Returns the version, which may be empty if a version was not present or /// was unparsable. llvm::VersionTuple getVersion() const { return Version; } /// Returns the kind of source of the module version. Do not call if /// \c isValid() returns false. ModuleVersionSourceKind getSourceKind() const { return SourceKind.value(); } void setVersion(llvm::VersionTuple version, ModuleVersionSourceKind kind) { Version = version; SourceKind = kind; } }; /// 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. /// /// If a non-null \p versionInfo is provided, the module version will be /// parsed and populated. virtual bool canImportModule(ImportPath::Module named, SourceLoc loc, ModuleVersionInfo *versionInfo, bool isTestableImport = false) = 0; /// 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. /// /// \param AllowMemoryCache Enables preserving the loaded module in the /// in-memory cache for the next loading attempt. /// /// \returns the module referenced, if it could be loaded. Otherwise, /// emits a diagnostic and returns NULL. virtual ModuleDecl *loadModule(SourceLoc importLoc, ImportPath::Module path, bool AllowMemoryCache = true) = 0; /// Load extensions to the given nominal type. /// /// \param nominal The nominal type whose extensions should be loaded. /// /// \param previousGeneration The previous generation number. The AST already /// contains extensions loaded from any generation up to and including this /// one. virtual void loadExtensions(NominalTypeDecl *nominal, unsigned previousGeneration) { } /// Load the methods within the given type that produce /// Objective-C class or instance methods with the given selector. /// /// \param typeDecl The type in which we are searching for @objc methods. /// The search only considers this type and its extensions; not any /// superclasses. /// /// \param selector The selector to search for. /// /// \param isInstanceMethod Whether we are looking for an instance method /// (vs. a class method). /// /// \param previousGeneration The previous generation with which this /// callback was invoked. The list of methods will already contain all of /// the results from generations up and including \c previousGeneration. /// /// \param methods The list of @objc methods in this class that have this /// selector and are instance/class methods as requested. This list will be /// extended with any methods found in subsequent generations. virtual void loadObjCMethods( NominalTypeDecl *typeDecl, ObjCSelector selector, bool isInstanceMethod, unsigned previousGeneration, llvm::TinyPtrVector &methods) = 0; /// Load derivative function configurations for the given /// AbstractFunctionDecl. /// /// \param originalAFD The declaration whose derivative function /// configurations should be loaded. /// /// \param previousGeneration The previous generation number. The AST already /// contains derivative function configurations loaded from any generation up /// to and including this one. /// /// \param results The result list of derivative function configurations. /// This list will be extended with any methods found in subsequent /// generations. virtual void loadDerivativeFunctionConfigurations( AbstractFunctionDecl *originalAFD, unsigned previousGeneration, llvm::SetVector &results) {}; /// Verify all modules loaded by this loader. virtual void verifyAllModules() { } /// Discover overlays declared alongside this file and add information about /// them to it. void findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module, FileUnit *file); /// Retrieve the dependencies for the given, named module, or \c None /// if no such module exists. virtual llvm::SmallVector, 1> getModuleDependencies(Identifier moduleName, StringRef moduleOutputPath, StringRef sdkModuleOutputPath, const llvm::DenseSet &alreadySeenClangModules, const std::vector &swiftModuleClangCC1CommandLineArgs, InterfaceSubContextDelegate &delegate, llvm::PrefixMapper *mapper = nullptr, bool isTestableImport = false) = 0; }; } // namespace swift namespace llvm { template <> struct DenseMapInfo { using MacroPluginDependency = swift::DependencyTracker::MacroPluginDependency; static MacroPluginDependency getEmptyKey() { return {DenseMapInfo::getEmptyKey(), ""}; } static MacroPluginDependency getTombstoneKey() { return {DenseMapInfo::getTombstoneKey(), ""}; } static unsigned getHashValue(MacroPluginDependency Val) { return hash_combine(Val.moduleName, Val.path); } static bool isEqual(const MacroPluginDependency &LHS, const MacroPluginDependency &RHS) { return LHS.moduleName == RHS.moduleName && LHS.path == RHS.path; } }; } // namespace llvm #endif