//===--- Module.h - Swift Language Module ASTs ------------------*- 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 defines the Module class and its subclasses. // //===----------------------------------------------------------------------===// #ifndef SWIFT_MODULE_H #define SWIFT_MODULE_H #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" #include "swift/AST/Identifier.h" #include "swift/AST/LookupKinds.h" #include "swift/AST/RawComment.h" #include "swift/AST/Type.h" #include "swift/Basic/Compiler.h" #include "swift/Basic/OptionSet.h" #include "swift/Basic/SourceLoc.h" #include "swift/Basic/STLExtras.h" #include "swift/Parse/Token.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" namespace clang { class Module; } namespace swift { enum class ArtificialMainKind : uint8_t; class ASTContext; class ASTScope; class ASTWalker; class BraceStmt; class Decl; class DeclAttribute; class TypeDecl; enum class DeclKind : uint8_t; class ExtensionDecl; class DebuggerClient; class DeclName; class FileUnit; class FuncDecl; class InfixOperatorDecl; class LinkLibrary; class LookupCache; class ModuleLoader; class NameAliasType; class NominalTypeDecl; class EnumElementDecl; class OperatorDecl; class PostfixOperatorDecl; class PrefixOperatorDecl; class ProtocolConformance; class ProtocolDecl; struct PrintOptions; class ReferencedNameTracker; class TupleType; class Type; class TypeRefinementContext; class ValueDecl; class VarDecl; class VisibleDeclConsumer; /// Discriminator for file-units. enum class FileUnitKind { /// For a .swift source file. Source, /// For the compiler Builtin module. Builtin, /// A serialized Swift AST. SerializedAST, /// An imported Clang module. ClangModule, /// A derived declaration. Derived, }; enum class SourceFileKind { Library, ///< A normal .swift file. Main, ///< A .swift file that can have top-level code. REPL, ///< A virtual file that holds the user's input in the REPL. SIL ///< Came from a .sil file. }; /// Discriminator for resilience strategy. enum class ResilienceStrategy : unsigned { /// Public nominal types: fragile /// Non-inlineable function bodies: resilient /// /// This is the default behavior without any flags. Default, /// Public nominal types: resilient /// Non-inlineable function bodies: resilient /// /// This is the behavior with -enable-resilience. Resilient, /// Public nominal types: fragile /// Non-inlineable function bodies: fragile /// /// This is the behavior with -sil-serialize-all. Fragile }; /// The minimum unit of compilation. /// /// A module is made up of several file-units, which are all part of the same /// output binary and logical module (such as a single library or executable). /// /// \sa FileUnit class ModuleDecl : public TypeDecl, public DeclContext { public: typedef ArrayRef> AccessPathTy; typedef std::pair ImportedModule; static bool matchesAccessPath(AccessPathTy AccessPath, DeclName Name) { assert(AccessPath.size() <= 1 && "can only refer to top-level decls"); return AccessPath.empty() || DeclName(AccessPath.front().first).matchesRef(Name); } /// Arbitrarily orders ImportedModule records, for inclusion in sets and such. class OrderImportedModules { public: bool operator()(const ImportedModule &lhs, const ImportedModule &rhs) const { if (lhs.second != rhs.second) return std::less()(lhs.second, rhs.second); if (lhs.first.data() != rhs.first.data()) return std::less()(lhs.first.begin(), rhs.first.begin()); return lhs.first.size() < rhs.first.size(); } }; private: /// If non-NULL, an plug-in that should be used when performing external /// lookups. // FIXME: Do we really need to bloat all modules with this? DebuggerClient *DebugClient = nullptr; SmallVector Files; /// Tracks the file that will generate the module's entry point, either /// because it contains a class marked with \@UIApplicationMain /// or \@NSApplicationMain, or because it is a script file. class EntryPointInfoTy { enum class Flags { DiagnosedMultipleMainClasses = 1 << 0, DiagnosedMainClassWithScript = 1 << 1 }; llvm::PointerIntPair> storage; public: EntryPointInfoTy() = default; FileUnit *getEntryPointFile() const { return storage.getPointer(); } void setEntryPointFile(FileUnit *file) { assert(!storage.getPointer()); storage.setPointer(file); } bool hasEntryPoint() const { return storage.getPointer(); } bool markDiagnosedMultipleMainClasses() { bool res = storage.getInt().contains(Flags::DiagnosedMultipleMainClasses); storage.setInt(storage.getInt() | Flags::DiagnosedMultipleMainClasses); return !res; } bool markDiagnosedMainClassWithScript() { bool res = storage.getInt().contains(Flags::DiagnosedMainClassWithScript); storage.setInt(storage.getInt() | Flags::DiagnosedMainClassWithScript); return !res; } }; /// Information about the file responsible for the module's entry point, /// if any. /// /// \see EntryPointInfoTy EntryPointInfoTy EntryPointInfo; struct { unsigned TestingEnabled : 1; unsigned FailedToLoad : 1; unsigned ResilienceStrategy : 2; } Flags; ModuleDecl(Identifier name, ASTContext &ctx); public: static ModuleDecl *create(Identifier name, ASTContext &ctx) { return new (ctx) ModuleDecl(name, ctx); } using Decl::getASTContext; ArrayRef getFiles() { return Files; } ArrayRef getFiles() const { return { Files.begin(), Files.size() }; } void addFile(FileUnit &newFile); void removeFile(FileUnit &existingFile); /// Convenience accessor for clients that know what kind of file they're /// dealing with. SourceFile &getMainSourceFile(SourceFileKind expectedKind) const; /// Convenience accessor for clients that know what kind of file they're /// dealing with. FileUnit &getMainFile(FileUnitKind expectedKind) const; DebuggerClient *getDebugClient() const { return DebugClient; } void setDebugClient(DebuggerClient *R) { assert(!DebugClient && "Debugger client already set"); DebugClient = R; } /// Returns true if this module was or is being compiled for testing. bool isTestingEnabled() const { return Flags.TestingEnabled; } void setTestingEnabled(bool enabled = true) { Flags.TestingEnabled = enabled; } /// Returns true if there was an error trying to load this module. bool failedToLoad() const { return Flags.FailedToLoad; } void setFailedToLoad(bool failed = true) { Flags.FailedToLoad = failed; } ResilienceStrategy getResilienceStrategy() const { return ResilienceStrategy(Flags.ResilienceStrategy); } void setResilienceStrategy(ResilienceStrategy strategy) { Flags.ResilienceStrategy = unsigned(strategy); } /// Look up a (possibly overloaded) value set at top-level scope /// (but with the specified access path, which may come from an import decl) /// within the current module. /// /// This does a simple local lookup, not recursively looking through imports. void lookupValue(AccessPathTy AccessPath, DeclName Name, NLKind LookupKind, SmallVectorImpl &Result) const; /// Look up a local type declaration by its mangled name. /// /// This does a simple local lookup, not recursively looking through imports. TypeDecl *lookupLocalType(StringRef MangledName) const; /// Find ValueDecls in the module and pass them to the given consumer object. /// /// This does a simple local lookup, not recursively looking through imports. void lookupVisibleDecls(AccessPathTy AccessPath, VisibleDeclConsumer &Consumer, NLKind LookupKind) const; /// @{ /// Look up the given operator in this module. /// /// If the operator is not found, or if there is an ambiguity, returns null. InfixOperatorDecl *lookupInfixOperator(Identifier name, SourceLoc diagLoc = {}); PrefixOperatorDecl *lookupPrefixOperator(Identifier name, SourceLoc diagLoc = {}); PostfixOperatorDecl *lookupPostfixOperator(Identifier name, SourceLoc diagLoc = {}); PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name, SourceLoc diagLoc = {}); /// @} /// Finds all class members defined in this module. /// /// This does a simple local lookup, not recursively looking through imports. void lookupClassMembers(AccessPathTy accessPath, VisibleDeclConsumer &consumer) const; /// Finds class members defined in this module with the given name. /// /// This does a simple local lookup, not recursively looking through imports. void lookupClassMember(AccessPathTy accessPath, DeclName name, SmallVectorImpl &results) const; /// Look for the conformance of the given type to the given protocol. /// /// This routine determines whether the given \c type conforms to the given /// \c protocol. /// /// \param type The type for which we are computing conformance. /// /// \param protocol The protocol to which we are computing conformance. /// /// \returns The result of the conformance search, which will be /// None if the type does not conform to the protocol or contain a /// ProtocolConformanceRef if it does conform. Optional lookupConformance(Type type, ProtocolDecl *protocol); /// Find a member named \p name in \p container that was declared in this /// module. /// /// \p container may be \c this for a top-level lookup. /// /// If \p privateDiscriminator is non-empty, only matching private decls are /// returned; otherwise, only non-private decls are returned. void lookupMember(SmallVectorImpl &results, DeclContext *container, DeclName name, Identifier privateDiscriminator) const; /// Find all Objective-C methods with the given selector. void lookupObjCMethods( ObjCSelector selector, SmallVectorImpl &results) const; /// \sa getImportedModules enum class ImportFilter { All, Public, Private }; /// Looks up which modules are imported by this module. /// /// \p filter controls whether public, private, or any imports are included /// in this list. void getImportedModules(SmallVectorImpl &imports, ImportFilter filter = ImportFilter::Public) const; /// Looks up which modules are imported by this module, ignoring any that /// won't contain top-level decls. /// /// This is a performance hack. Do not use for anything but name lookup. /// May go away in the future. void getImportedModulesForLookup(SmallVectorImpl &imports) const; /// Finds all top-level decls of this module. /// /// This does a simple local lookup, not recursively looking through imports. /// The order of the results is not guaranteed to be meaningful. void getTopLevelDecls(SmallVectorImpl &Results) const; /// Finds all local type decls of this module. /// /// This does a simple local lookup, not recursively looking through imports. /// The order of the results is not guaranteed to be meaningful. void getLocalTypeDecls(SmallVectorImpl &Results) const; /// Finds all top-level decls that should be displayed to a client of this /// module. /// /// This includes types, variables, functions, and extensions. /// This does a simple local lookup, not recursively looking through imports. /// The order of the results is not guaranteed to be meaningful. /// /// This can differ from \c getTopLevelDecls, e.g. it returns decls from a /// shadowed clang module. void getDisplayDecls(SmallVectorImpl &results) const; /// @{ /// Perform an action for every module visible from this module. /// /// This only includes modules with at least one declaration visible: if two /// import access paths are incompatible, the indirect module will be skipped. /// Modules that can't be used for lookup (including Clang submodules at the /// time this comment was written) are also skipped under certain /// circumstances. /// /// \param topLevelAccessPath If present, include the top-level module in the /// results, with the given access path. /// \param includePrivateTopLevelImports If true, imports listed in all /// file units within this module are traversed. Otherwise (the /// default), only re-exported imports are traversed. /// \param fn A callback of type bool(ImportedModule) or void(ImportedModule). /// Return \c false to abort iteration. /// /// \return True if the traversal ran to completion, false if it ended early /// due to the callback. bool forAllVisibleModules(AccessPathTy topLevelAccessPath, bool includePrivateTopLevelImports, llvm::function_ref fn); bool forAllVisibleModules(AccessPathTy topLevelAccessPath, bool includePrivateTopLevelImports, llvm::function_ref fn) { return forAllVisibleModules(topLevelAccessPath, includePrivateTopLevelImports, [=](const ImportedModule &import) -> bool { fn(import); return true; }); } template bool forAllVisibleModules(AccessPathTy topLevelAccessPath, bool includePrivateTopLevelImports, Fn &&fn) { using RetTy = typename std::result_of::type; llvm::function_ref wrapped{std::forward(fn)}; return forAllVisibleModules(topLevelAccessPath, includePrivateTopLevelImports, wrapped); } template bool forAllVisibleModules(AccessPathTy topLevelAccessPath, Fn &&fn) { return forAllVisibleModules(topLevelAccessPath, false, std::forward(fn)); } /// @} using LinkLibraryCallback = llvm::function_ref; /// Generate the list of libraries needed to link this module, based on its /// imports. void collectLinkLibraries(LinkLibraryCallback callback); /// Returns true if the two access paths contain the same chain of /// identifiers. /// /// Source locations are ignored here. static bool isSameAccessPath(AccessPathTy lhs, AccessPathTy rhs); /// \brief Get the path for the file that this module came from, or an empty /// string if this is not applicable. StringRef getModuleFilename() const; /// \returns true if this module is the "swift" standard library module. bool isStdlibModule() const; /// \returns true if this module is the "SwiftShims" module; bool isSwiftShimsModule() const; /// \returns true if this module is the "builtin" module. bool isBuiltinModule() const; /// \returns true if this module is a system module; note that the StdLib is /// considered a system module. bool isSystemModule() const; /// \returns true if traversal was aborted, false otherwise. bool walk(ASTWalker &Walker); /// Register the file responsible for generating this module's entry point. /// /// \returns true if there was a problem adding this file. bool registerEntryPointFile(FileUnit *file, SourceLoc diagLoc, Optional kind); /// \returns true if this module has a main entry point. bool hasEntryPoint() const { return EntryPointInfo.hasEntryPoint(); } /// Returns the associated clang module if one exists. const clang::Module *findUnderlyingClangModule(); SourceRange getSourceRange() const { return SourceRange(); } static bool classof(const DeclContext *DC) { return DC->getContextKind() == DeclContextKind::Module; } static bool classof(const Decl *D) { return D->getKind() == DeclKind::Module; } private: // Make placement new and vanilla new/delete illegal for Modules. void *operator new(size_t Bytes) throw() = delete; void operator delete(void *Data) throw() SWIFT_DELETE_OPERATOR_DELETED; void *operator new(size_t Bytes, void *Mem) throw() = delete; public: // Only allow allocation of Modules using the allocator in ASTContext // or by doing a placement new. void *operator new(size_t Bytes, const ASTContext &C, unsigned Alignment = alignof(ModuleDecl)); }; static inline unsigned alignOfFileUnit(); /// A container for module-scope declarations that itself provides a scope; the /// smallest unit of code organization. /// /// FileUnit is an abstract base class; its subclasses represent different /// sorts of containers that can each provide a set of decls, e.g. a source /// file. A module can contain several file-units. class FileUnit : public DeclContext { virtual void anchor(); // FIXME: Stick this in a PointerIntPair. const FileUnitKind Kind; protected: FileUnit(FileUnitKind kind, ModuleDecl &M) : DeclContext(DeclContextKind::FileUnit, &M), Kind(kind) { } virtual ~FileUnit() = default; public: FileUnitKind getKind() const { return Kind; } /// Look up a (possibly overloaded) value set at top-level scope /// (but with the specified access path, which may come from an import decl) /// within this file. /// /// This does a simple local lookup, not recursively looking through imports. virtual void lookupValue(ModuleDecl::AccessPathTy accessPath, DeclName name, NLKind lookupKind, SmallVectorImpl &result) const = 0; /// Look up a local type declaration by its mangled name. /// /// This does a simple local lookup, not recursively looking through imports. virtual TypeDecl *lookupLocalType(StringRef MangledName) const { return nullptr; } /// Directly look for a nested type declared within this module inside the /// given nominal type (including any extensions). /// /// This is a fast-path hack to avoid circular dependencies in deserialization /// and the Clang importer. /// /// Private and fileprivate types should not be returned by this lookup. virtual TypeDecl *lookupNestedType(Identifier name, const NominalTypeDecl *parent) const { return nullptr; } /// Find ValueDecls in the module and pass them to the given consumer object. /// /// This does a simple local lookup, not recursively looking through imports. virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, VisibleDeclConsumer &consumer, NLKind lookupKind) const {} /// Finds all class members defined in this file. /// /// This does a simple local lookup, not recursively looking through imports. virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, VisibleDeclConsumer &consumer) const {} /// Finds class members defined in this file with the given name. /// /// This does a simple local lookup, not recursively looking through imports. virtual void lookupClassMember(ModuleDecl::AccessPathTy accessPath, DeclName name, SmallVectorImpl &results) const {} /// Find all Objective-C methods with the given selector. virtual void lookupObjCMethods( ObjCSelector selector, SmallVectorImpl &results) const = 0; /// Returns the comment attached to the given declaration. /// /// This function is an implementation detail for comment serialization. /// If you just want to get a comment attached to a decl, use /// \c Decl::getRawComment() or \c Decl::getBriefComment(). virtual Optional getCommentForDecl(const Decl *D) const { return None; } virtual Optional getGroupNameForDecl(const Decl *D) const { return None; } virtual Optional getSourceFileNameForDecl(const Decl *D) const { return None; } virtual Optional getSourceOrderForDecl(const Decl *D) const { return None; } virtual Optional getGroupNameByUSR(StringRef USR) const { return None; } virtual void collectAllGroups(std::vector &Names) const {} /// Returns an implementation-defined "discriminator" for \p D, which /// distinguishes \p D from other declarations in the same module with the /// same name. /// /// Since this value is used in name mangling, it should be a valid ASCII-only /// identifier. virtual Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const = 0; /// Finds all top-level decls in this file. /// /// This does a simple local lookup, not recursively looking through imports. /// The order of the results is not guaranteed to be meaningful. virtual void getTopLevelDecls(SmallVectorImpl &results) const {} /// Finds all local type decls in this file. /// /// This does a simple local lookup, not recursively looking through imports. /// The order of the results is not guaranteed to be meaningful. virtual void getLocalTypeDecls(SmallVectorImpl &results) const {} /// Adds all top-level decls to the given vector. /// /// This includes all decls that should be displayed to clients of the module. /// The order of the results is not guaranteed to be meaningful. /// /// This can differ from \c getTopLevelDecls, e.g. it returns decls from a /// shadowed clang module. virtual void getDisplayDecls(SmallVectorImpl &results) const { getTopLevelDecls(results); } /// Looks up which modules are imported by this file. /// /// \p filter controls whether public, private, or any imports are included /// in this list. virtual void getImportedModules(SmallVectorImpl &imports, ModuleDecl::ImportFilter filter) const {} /// \see ModuleDecl::getImportedModulesForLookup virtual void getImportedModulesForLookup( SmallVectorImpl &imports) const { return getImportedModules(imports, ModuleDecl::ImportFilter::Public); } /// Generates the list of libraries needed to link this file, based on its /// imports. virtual void collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {} /// @{ /// Perform an action for every module visible from this file. /// /// \param fn A callback of type bool(ImportedModule) or void(ImportedModule). /// Return \c false to abort iteration. /// /// \return True if the traversal ran to completion, false if it ended early /// due to the callback. bool forAllVisibleModules(llvm::function_ref fn); bool forAllVisibleModules(llvm::function_ref fn) { return forAllVisibleModules([=](ModuleDecl::ImportedModule import) -> bool { fn(import); return true; }); } template bool forAllVisibleModules(Fn &&fn) { using RetTy = typename std::result_of::type; llvm::function_ref wrapped{ std::forward(fn) }; return forAllVisibleModules(wrapped); } /// @} /// True if this file contains the main class for the module. bool hasMainClass() const { return getMainClass(); } virtual ClassDecl *getMainClass() const { assert(hasEntryPoint()); return nullptr; } virtual bool hasEntryPoint() const { return false; } /// Returns the associated clang module if one exists. virtual const clang::Module *getUnderlyingClangModule() { return nullptr; } /// Traverse the decls within this file. /// /// \returns true if traversal was aborted, false if it completed /// successfully. virtual bool walk(ASTWalker &walker); // Efficiency override for DeclContext::getParentModule(). ModuleDecl *getParentModule() const { return const_cast(cast(getParent())); } static bool classof(const DeclContext *DC) { return DC->getContextKind() == DeclContextKind::FileUnit; } private: // Make placement new and vanilla new/delete illegal for FileUnits. void *operator new(size_t Bytes) throw() = delete; void *operator new(size_t Bytes, void *Mem) throw() = delete; protected: // Unfortunately we can't remove this altogether because the virtual // destructor requires it to be accessible. void operator delete(void *Data) throw() { llvm_unreachable("Don't use operator delete on a SourceFile"); } public: // Only allow allocation of FileUnits using the allocator in ASTContext // or by doing a placement new. void *operator new(size_t Bytes, ASTContext &C, unsigned Alignment = alignOfFileUnit()); }; static inline unsigned alignOfFileUnit() { return alignof(FileUnit&); } /// A file containing Swift source code. /// /// This is a .swift or .sil file (or a virtual file, such as the contents of /// the REPL). Since it contains raw source, it must be parsed and name-bound /// before being used for anything; a full type-check is also necessary for /// IR generation. class SourceFile final : public FileUnit { public: class LookupCache; class Impl; /// The implicit module import that the SourceFile should get. enum class ImplicitModuleImportKind { None, Builtin, Stdlib }; /// Possible attributes for imports in source files. enum class ImportFlags { /// The imported module is exposed to anyone who imports the parent module. Exported = 0x1, /// This source file has access to testable declarations in the imported /// module. Testable = 0x2 }; /// \see ImportFlags using ImportOptions = OptionSet; private: std::unique_ptr Cache; LookupCache &getCache() const; /// This is the list of modules that are imported by this module. /// /// This is filled in by the Name Binding phase. ArrayRef> Imports; /// A unique identifier representing this file; used to mark private decls /// within the file to keep them from conflicting with other files in the /// same module. mutable Identifier PrivateDiscriminator; /// The root TypeRefinementContext for this SourceFile. /// /// This is set during type checking. TypeRefinementContext *TRC = nullptr; /// If non-null, used to track name lookups that happen within this file. ReferencedNameTracker *ReferencedNames = nullptr; /// The class in this file marked \@NS/UIApplicationMain. ClassDecl *MainClass = nullptr; /// The source location of the main class. SourceLoc MainClassDiagLoc; /// A hash of all interface-contributing tokens that have been lexed for /// this source file so far. llvm::MD5 InterfaceHash; /// \brief The ID for the memory buffer containing this file's source. /// /// May be -1, to indicate no association with a buffer. int BufferID; /// The list of protocol conformances that were "used" within this /// source file. llvm::SetVector UsedConformances; /// The scope map that describes this source file. ASTScope *Scope = nullptr; friend ASTContext; friend Impl; ~SourceFile(); public: /// The list of top-level declarations in the source file. std::vector Decls; /// The list of local type declarations in the source file. llvm::SetVector LocalTypeDecls; /// A set of special declaration attributes which require the /// Foundation module to be imported to work. If the foundation /// module is still not imported by the time type checking is /// complete, we diagnose. llvm::SetVector AttrsRequiringFoundation; /// A mapping from Objective-C selectors to the methods that have /// those selectors. llvm::DenseMap> ObjCMethods; template using OperatorMap = llvm::DenseMap>; OperatorMap InfixOperators; OperatorMap PostfixOperators; OperatorMap PrefixOperators; OperatorMap PrecedenceGroups; /// Describes what kind of file this is, which can affect some type checking /// and other behavior. const SourceFileKind Kind; enum ASTStage_t { /// Parsing is underway. Parsing, /// Parsing has completed. Parsed, /// Name binding has completed. NameBound, /// Type checking has completed. TypeChecked }; /// Defines what phases of parsing and semantic analysis are complete for a /// source file. /// /// Only files that have been fully processed (i.e. type-checked) will be /// forwarded on to IRGen. ASTStage_t ASTStage = Parsing; SourceFile(ModuleDecl &M, SourceFileKind K, Optional bufferID, ImplicitModuleImportKind ModImpKind, bool KeepTokens); void addImports(ArrayRef> IM); bool hasTestableImport(const ModuleDecl *module) const; void clearLookupCache(); void cacheVisibleDecls(SmallVectorImpl &&globals) const; const SmallVectorImpl &getCachedVisibleDecls() const; virtual void lookupValue(ModuleDecl::AccessPathTy accessPath, DeclName name, NLKind lookupKind, SmallVectorImpl &result) 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 &results) const override; void lookupObjCMethods( ObjCSelector selector, SmallVectorImpl &results) const override; virtual void getTopLevelDecls(SmallVectorImpl &results) const override; virtual void getLocalTypeDecls(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; Identifier getPrivateDiscriminator() const { return PrivateDiscriminator; } virtual bool walk(ASTWalker &walker) override; /// Note that the given conformance was used by this source file. void addUsedConformance(NormalProtocolConformance *conformance) { UsedConformances.insert(conformance); } /// Retrieve the set of conformances that were used in this source /// file. ArrayRef getUsedConformances() const { return UsedConformances.getArrayRef(); } /// @{ /// Look up the given operator in this file. /// /// The file must be name-bound already. If the operator is not found, or if /// there is an ambiguity, returns null. /// /// \param isCascading If true, the lookup of this operator may affect /// downstream files. InfixOperatorDecl *lookupInfixOperator(Identifier name, bool isCascading, SourceLoc diagLoc = {}); PrefixOperatorDecl *lookupPrefixOperator(Identifier name, bool isCascading, SourceLoc diagLoc = {}); PostfixOperatorDecl *lookupPostfixOperator(Identifier name, bool isCascading, SourceLoc diagLoc = {}); PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name, bool isCascading, SourceLoc diagLoc = {}); /// @} ReferencedNameTracker *getReferencedNameTracker() const { return ReferencedNames; } void setReferencedNameTracker(ReferencedNameTracker *Tracker) { assert(!ReferencedNames && "This file already has a name tracker."); ReferencedNames = Tracker; } /// \brief The buffer ID for the file that was imported, or None if there /// is no associated buffer. Optional getBufferID() const { if (BufferID == -1) return None; return BufferID; } /// If this buffer corresponds to a file on disk, returns the path. /// Otherwise, return an empty string. StringRef getFilename() const; /// Retrieve the scope that describes this source file. ASTScope &getScope(); void dump() const; void dump(raw_ostream &os) const; /// \brief Pretty-print the contents of this source file. /// /// \param Printer The AST printer used for printing the contents. /// \param PO Options controlling the printing process. void print(ASTPrinter &Printer, const PrintOptions &PO); void print(raw_ostream &OS, const PrintOptions &PO); static bool classof(const FileUnit *file) { return file->getKind() == FileUnitKind::Source; } static bool classof(const DeclContext *DC) { return isa(DC) && classof(cast(DC)); } /// True if this is a "script mode" source file that admits top-level code. bool isScriptMode() const { switch (Kind) { case SourceFileKind::Main: case SourceFileKind::REPL: return true; case SourceFileKind::Library: case SourceFileKind::SIL: return false; } llvm_unreachable("bad SourceFileKind"); } ClassDecl *getMainClass() const override { return MainClass; } SourceLoc getMainClassDiagLoc() const { assert(hasMainClass()); return MainClassDiagLoc; } /// Register a "main" class for the module, complaining if there is more than /// one. /// /// Should only be called during type-checking. bool registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc); /// True if this source file has an application entry point. /// /// This is true if the source file either is in script mode or contains /// a designated main class. bool hasEntryPoint() const override { return isScriptMode() || hasMainClass(); } /// Get the root refinement context for the file. The root context may be /// null if the context hierarchy has not been built yet. Use /// TypeChecker::getOrBuildTypeRefinementContext() to get a built /// root of the hierarchy. TypeRefinementContext *getTypeRefinementContext(); /// Set the root refinement context for the file. void setTypeRefinementContext(TypeRefinementContext *TRC); void recordInterfaceToken(StringRef token) { assert(!token.empty()); InterfaceHash.update(token); // Add null byte to separate tokens. uint8_t a[1] = {0}; InterfaceHash.update(a); } const llvm::MD5 &getInterfaceHashState() { return InterfaceHash; } void setInterfaceHashState(const llvm::MD5 &state) { InterfaceHash = state; } void getInterfaceHash(llvm::SmallString<32> &str) { llvm::MD5::MD5Result result; InterfaceHash.final(result); llvm::MD5::stringifyResult(result, str); } void dumpInterfaceHash(llvm::raw_ostream &out) { llvm::SmallString<32> str; getInterfaceHash(str); out << str << '\n'; } std::vector &getTokenVector() { assert(pAllCorrectedTokens && "Disabled"); return *pAllCorrectedTokens; } ArrayRef getAllTokens() const { assert(pAllCorrectedTokens && "Disabled"); return *pAllCorrectedTokens; } bool shouldKeepTokens() const { return (bool)pAllCorrectedTokens; } private: /// If not null, the pointee vector should contain tokens of this source file. std::unique_ptr> pAllCorrectedTokens; }; /// This represents the compiler's implicitly generated declarations in the /// Builtin module. class BuiltinUnit final : public FileUnit { public: class LookupCache; private: std::unique_ptr Cache; LookupCache &getCache() const; friend ASTContext; ~BuiltinUnit() = default; public: explicit BuiltinUnit(ModuleDecl &M); virtual void lookupValue(ModuleDecl::AccessPathTy accessPath, DeclName name, NLKind lookupKind, SmallVectorImpl &result) const override; /// Find all Objective-C methods with the given selector. void lookupObjCMethods( ObjCSelector selector, SmallVectorImpl &results) const override; Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override { llvm_unreachable("no private values in the Builtin module"); } static bool classof(const FileUnit *file) { return file->getKind() == FileUnitKind::Builtin; } static bool classof(const DeclContext *DC) { return isa(DC) && classof(cast(DC)); } }; /// Represents an externally-loaded file of some kind. class LoadedFile : public FileUnit { protected: ~LoadedFile() = default; LoadedFile(FileUnitKind Kind, ModuleDecl &M) noexcept : FileUnit(Kind, M) { assert(classof(this) && "invalid kind"); } public: /// Returns an arbitrary string representing the storage backing this file. /// /// This is usually a filesystem path. virtual StringRef getFilename() const; /// Look up an operator declaration. /// /// \param name The operator name ("+", ">>", etc.) /// /// \param fixity One of PrefixOperator, InfixOperator, or PostfixOperator. virtual OperatorDecl *lookupOperator(Identifier name, DeclKind fixity) const { return nullptr; } /// Look up a precedence group. /// /// \param name The precedence group name. virtual PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name) const { return nullptr; } virtual bool isSystemModule() const { return false; } static bool classof(const FileUnit *file) { return file->getKind() == FileUnitKind::SerializedAST || file->getKind() == FileUnitKind::ClangModule; } static bool classof(const DeclContext *DC) { return isa(DC) && classof(cast(DC)); } }; inline SourceFile & ModuleDecl::getMainSourceFile(SourceFileKind expectedKind) const { assert(!Files.empty() && "No files added yet"); assert(cast(Files.front())->Kind == expectedKind); return *cast(Files.front()); } inline FileUnit &ModuleDecl::getMainFile(FileUnitKind expectedKind) const { assert(expectedKind != FileUnitKind::Source && "must use specific source kind; see getMainSourceFile"); assert(!Files.empty() && "No files added yet"); assert(Files.front()->getKind() == expectedKind); return *Files.front(); } /// Wraps either a swift module or a clang one. /// FIXME: Should go away once swift modules can support submodules natively. class ModuleEntity { llvm::PointerUnion Mod; public: ModuleEntity() = default; ModuleEntity(const ModuleDecl *Mod) : Mod(Mod) {} ModuleEntity(const clang::Module *Mod) : Mod(static_cast(Mod)){} StringRef getName() const; std::string getFullName() const; bool isSystemModule() const; bool isBuiltinModule() const; const ModuleDecl *getAsSwiftModule() const; explicit operator bool() const { return !Mod.isNull(); } }; } // end namespace swift namespace llvm { template <> class DenseMapInfo { using ModuleDecl = swift::ModuleDecl; public: static ModuleDecl::ImportedModule getEmptyKey() { return {{}, llvm::DenseMapInfo::getEmptyKey()}; } static ModuleDecl::ImportedModule getTombstoneKey() { return {{}, llvm::DenseMapInfo::getTombstoneKey()}; } static unsigned getHashValue(const ModuleDecl::ImportedModule &val) { auto pair = std::make_pair(val.first.size(), val.second); return llvm::DenseMapInfo::getHashValue(pair); } static bool isEqual(const ModuleDecl::ImportedModule &lhs, const ModuleDecl::ImportedModule &rhs) { return lhs.second == rhs.second && ModuleDecl::isSameAccessPath(lhs.first, rhs.first); } }; } #endif