//===--- ModuleDependencyScanner.h - Import Swift modules --------*- C++ //-*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2020 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 // //===----------------------------------------------------------------------===// #include "swift/AST/ASTContext.h" #include "swift/AST/Identifier.h" #include "swift/AST/ModuleDependencies.h" #include "swift/Frontend/ModuleInterfaceLoader.h" #include "swift/Serialization/SerializedModuleLoader.h" #include "llvm/CAS/CASReference.h" #include "llvm/Support/ThreadPool.h" namespace swift { class DependencyTracker; } namespace swift { /// A dependency scanning worker which performs filesystem lookup /// of a named module dependency. class ModuleDependencyScanningWorker { public: ModuleDependencyScanningWorker( SwiftDependencyScanningService &globalScanningService, const CompilerInvocation &ScanCompilerInvocation, const SILOptions &SILOptions, ASTContext &ScanASTContext, DependencyTracker &DependencyTracker, DiagnosticEngine &diags); private: /// Retrieve the module dependencies for the Clang module with the given name. ModuleDependencyVector scanFilesystemForClangModuleDependency( Identifier moduleName, StringRef moduleOutputPath, StringRef sdkModuleOutputPath, const llvm::DenseSet &alreadySeenModules, llvm::PrefixMapper *prefixMapper); /// Retrieve the module dependencies for the Swift module with the given name. ModuleDependencyVector scanFilesystemForSwiftModuleDependency( Identifier moduleName, StringRef moduleOutputPath, StringRef sdkModuleOutputPath, llvm::PrefixMapper *prefixMapper, bool isTestableImport = false); /// Store cache entry for include tree. llvm::Error createCacheKeyForEmbeddedHeader(std::string embeddedHeaderIncludeTree, std::string chainedHeaderIncludeTree); // Worker-specific instance of CompilerInvocation std::unique_ptr workerCompilerInvocation; // Worker-specific instance of ASTContext std::unique_ptr workerASTContext; // An AST delegate for interface scanning. std::unique_ptr scanningASTDelegate; // The Clang scanner tool used by this worker. clang::tooling::dependencies::DependencyScanningTool clangScanningTool; // Swift and Clang module loaders acting as scanners. std::unique_ptr swiftScannerModuleLoader; std::unique_ptr clangScannerModuleLoader; // CAS instance. std::shared_ptr CAS; std::shared_ptr ActionCache; // Restrict access to the parent scanner class. friend class ModuleDependencyScanner; }; class ModuleDependencyScanner { public: ModuleDependencyScanner(SwiftDependencyScanningService &ScanningService, const CompilerInvocation &ScanCompilerInvocation, const SILOptions &SILOptions, ASTContext &ScanASTContext, DependencyTracker &DependencyTracker, DiagnosticEngine &diags, bool ParallelScan); /// Identify the scanner invocation's main module's dependencies llvm::ErrorOr getMainModuleDependencyInfo(ModuleDecl *mainModule); /// Resolve module dependencies of the given module, computing a full /// transitive closure dependency graph. std::vector performDependencyScan(ModuleDependencyID rootModuleID, ModuleDependenciesCache &cache); /// Query the module dependency info for the Clang module with the given name. /// Explicit by-name lookups are useful for batch mode scanning. std::optional getNamedClangModuleDependencyInfo(StringRef moduleName, ModuleDependenciesCache &cache, ModuleDependencyIDSetVector &discoveredClangModules); /// Query the module dependency info for the Swift module with the given name. /// Explicit by-name lookups are useful for batch mode scanning. std::optional getNamedSwiftModuleDependencyInfo(StringRef moduleName, ModuleDependenciesCache &cache); /// How many filesystem lookups were performed by the scanner unsigned getNumLookups() { return NumLookups; } private: /// Main routine that computes imported module dependency transitive /// closure for the given module. /// 1. Swift modules imported directly or via another Swift dependency /// 2. Clang modules imported directly or via a Swift dependency /// 3. Clang modules imported via textual header inputs to Swift modules /// (bridging headers) /// 4. Swift overlay modules of all of the transitively imported Clang modules /// that have one ModuleDependencyIDSetVector resolveImportedModuleDependencies(const ModuleDependencyID &rootModuleID, ModuleDependenciesCache &cache); void resolveSwiftModuleDependencies( const ModuleDependencyID &rootModuleID, ModuleDependenciesCache &cache, ModuleDependencyIDSetVector &discoveredSwiftModules); void resolveAllClangModuleDependencies( ArrayRef swiftModules, ModuleDependenciesCache &cache, ModuleDependencyIDSetVector &discoveredClangModules); void resolveHeaderDependencies( ArrayRef swiftModules, ModuleDependenciesCache &cache, ModuleDependencyIDSetVector &discoveredHeaderDependencyClangModules); void resolveSwiftOverlayDependencies( ArrayRef swiftModules, ModuleDependenciesCache &cache, ModuleDependencyIDSetVector &discoveredDependencies); /// Resolve all of a given module's imports to a Swift module, if one exists. void resolveSwiftImportsForModule( const ModuleDependencyID &moduleID, ModuleDependenciesCache &cache, ModuleDependencyIDSetVector &importedSwiftDependencies); /// If a module has a bridging header or other header inputs, execute a /// dependency scan on it and record the dependencies. void resolveHeaderDependenciesForModule( const ModuleDependencyID &moduleID, ModuleDependenciesCache &cache, ModuleDependencyIDSetVector &headerClangModuleDependencies); /// Resolve all module dependencies comprised of Swift overlays /// of this module's Clang module dependencies. void resolveSwiftOverlayDependenciesForModule( const ModuleDependencyID &moduleID, ModuleDependenciesCache &cache, ModuleDependencyIDSetVector &swiftOverlayDependencies); /// Identify all cross-import overlay module dependencies of the /// source module under scan and apply an action for each. void resolveCrossImportOverlayDependencies( StringRef mainModuleName, ModuleDependenciesCache &cache, llvm::function_ref action); /// Performance BridgingHeader Chaining. llvm::Error performBridgingHeaderChaining(const ModuleDependencyID &rootModuleID, ModuleDependenciesCache &cache, ModuleDependencyIDSetVector &allModules); /// Perform an operation utilizing one of the Scanning workers /// available to this scanner. template auto withDependencyScanningWorker(Function &&F, Args &&...ArgList); Identifier getModuleImportIdentifier(StringRef moduleName); private: const CompilerInvocation &ScanCompilerInvocation; ASTContext &ScanASTContext; DiagnosticEngine &Diagnostics; /// The available pool of workers for filesystem module search unsigned NumThreads; std::list> Workers; llvm::DefaultThreadPool ScanningThreadPool; /// Protect worker access. std::mutex WorkersLock; /// Count of filesystem queries performed std::atomic NumLookups = 0; }; } // namespace swift