| //===--- ImportCache.h - Caching the import graph ---------------*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2019 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 defines interfaces for querying the module import graph in an |
| // efficient manner. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_AST_IMPORT_CACHE_H |
| #define SWIFT_AST_IMPORT_CACHE_H |
| |
| #include "swift/AST/Module.h" |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/FoldingSet.h" |
| |
| namespace swift { |
| class DeclContext; |
| |
| namespace namelookup { |
| |
| /// An object describing a set of modules visible from a DeclContext. |
| /// |
| /// This consists of two arrays of modules; the top-level imports and the |
| /// transitive imports. |
| /// |
| /// The top-level imports contains all public imports of the parent module |
| /// of 'dc', together with any private imports in the source file containing |
| /// 'dc', if there is one. |
| /// |
| /// The transitive imports contains all public imports reachable from the |
| /// set of top-level imports. |
| /// |
| /// Both sets only contain unique elements. The top-level imports always |
| /// include the parent module of 'dc' explicitly. |
| /// |
| /// The set of transitive imports does not contain any elements found in |
| /// the top-level imports. |
| /// |
| /// The Swift standard library module is not included in either set unless |
| /// it was explicitly imported (or re-exported). |
| class ImportSet final : |
| public llvm::FoldingSetNode, |
| private llvm::TrailingObjects<ImportSet, ImportedModule> { |
| friend TrailingObjects; |
| friend class ImportCache; |
| |
| unsigned HasHeaderImportModule : 1; |
| unsigned NumTopLevelImports : 31; |
| unsigned NumTransitiveImports; |
| |
| ImportSet(bool hasHeaderImportModule, |
| ArrayRef<ImportedModule> topLevelImports, |
| ArrayRef<ImportedModule> transitiveImports); |
| |
| ImportSet(const ImportSet &) = delete; |
| void operator=(const ImportSet &) = delete; |
| |
| public: |
| void Profile(llvm::FoldingSetNodeID &ID) { |
| Profile(ID, getTopLevelImports()); |
| } |
| static void Profile( |
| llvm::FoldingSetNodeID &ID, |
| ArrayRef<ImportedModule> topLevelImports); |
| |
| size_t numTrailingObjects(OverloadToken<ImportedModule>) const { |
| return NumTopLevelImports + NumTransitiveImports; |
| } |
| |
| /// This is a bit of a hack to make module name lookup work properly. |
| /// If our import set includes the ClangImporter's special header import |
| /// module, we have to check it first, before any other imported module. |
| bool hasHeaderImportModule() const { |
| return HasHeaderImportModule; |
| } |
| |
| ArrayRef<ImportedModule> getTopLevelImports() const { |
| return {getTrailingObjects<ImportedModule>(), |
| NumTopLevelImports}; |
| } |
| |
| ArrayRef<ImportedModule> getTransitiveImports() const { |
| return {getTrailingObjects<ImportedModule>() + |
| NumTopLevelImports, |
| NumTransitiveImports}; |
| } |
| |
| ArrayRef<ImportedModule> getAllImports() const { |
| return {getTrailingObjects<ImportedModule>(), |
| NumTopLevelImports + NumTransitiveImports}; |
| } |
| }; |
| |
| class alignas(ImportedModule) ImportCache { |
| ImportCache(const ImportCache &) = delete; |
| void operator=(const ImportCache &) = delete; |
| |
| llvm::FoldingSet<ImportSet> ImportSets; |
| llvm::DenseMap<const DeclContext *, ImportSet *> ImportSetForDC; |
| llvm::DenseMap<std::tuple<const ModuleDecl *, |
| const DeclContext *>, |
| ArrayRef<ImportPath::Access>> VisibilityCache; |
| llvm::DenseMap<std::tuple<const ModuleDecl *, |
| const ModuleDecl *, |
| const DeclContext *>, |
| ArrayRef<ImportPath::Access>> ShadowCache; |
| |
| ImportPath::Access EmptyAccessPath; |
| |
| ArrayRef<ImportPath::Access> allocateArray( |
| ASTContext &ctx, |
| SmallVectorImpl<ImportPath::Access> &results); |
| |
| ImportSet &getImportSet(ASTContext &ctx, |
| ArrayRef<ImportedModule> topLevelImports); |
| |
| public: |
| ImportCache() {} |
| |
| /// Returns an object descripting all modules transtiively imported |
| /// from 'dc'. |
| ImportSet &getImportSet(const DeclContext *dc); |
| |
| /// Returns all access paths into 'mod' that are visible from 'dc', |
| /// including transitively, via re-exports. |
| ArrayRef<ImportPath::Access> |
| getAllVisibleAccessPaths(const ModuleDecl *mod, const DeclContext *dc); |
| |
| bool isImportedBy(const ModuleDecl *mod, |
| const DeclContext *dc) { |
| return !getAllVisibleAccessPaths(mod, dc).empty(); |
| } |
| |
| /// Returns all access paths in 'mod' that are visible from 'dc' if we |
| /// subtract imports of 'other'. |
| ArrayRef<ImportPath::Access> |
| getAllAccessPathsNotShadowedBy(const ModuleDecl *mod, |
| const ModuleDecl *other, |
| const DeclContext *dc); |
| |
| /// This is a hack to cope with main file parsing and REPL parsing, where |
| /// we can add ImportDecls after import resolution. |
| void clear() { |
| ImportSetForDC.clear(); |
| } |
| }; |
| |
| ArrayRef<ImportedModule> getAllImports(const DeclContext *dc); |
| |
| } // namespace namelookup |
| |
| } // namespace swift |
| |
| #endif |