//===--- SwiftLookupTable.h - Swift Lookup Table ----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements support for Swift name lookup tables stored in Clang // modules. // //===----------------------------------------------------------------------===// #ifndef SWIFT_CLANGIMPORTER_SWIFTLOOKUPTABLE_H #define SWIFT_CLANGIMPORTER_SWIFTLOOKUPTABLE_H #include "swift/Basic/LLVM.h" #include "swift/AST/Identifier.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ModuleFileExtension.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" #include #include namespace llvm { class BitstreamWriter; } namespace clang { class NamedDecl; class DeclContext; class MacroInfo; class ObjCCategoryDecl; class TypedefNameDecl; } namespace swift { /// The context into which a Clang declaration will be imported. /// /// When the context into which a declaration will be imported matches /// a Clang declaration context (the common case), the result will be /// expressed as a declaration context. Otherwise, if the Clang type /// is not itself a declaration context (for example, a typedef that /// comes into Swift as a strong type), the Clang type declaration /// will be provided. Finally, if the context is known only via its /// Swift name, this will be recorded as class EffectiveClangContext { public: enum Kind { DeclContext, TypedefContext, UnresolvedContext, }; private: Kind TheKind; union { clang::DeclContext *DC; clang::TypedefNameDecl *Typedef; struct { const char *Data; unsigned Length; } Unresolved; }; public: EffectiveClangContext() : TheKind(DeclContext) { DC = nullptr; } EffectiveClangContext(clang::DeclContext *dc) : TheKind(DeclContext) { DC = dc; } EffectiveClangContext(clang::TypedefNameDecl *typedefName) : TheKind(TypedefContext) { Typedef = typedefName; } EffectiveClangContext(StringRef unresolved) : TheKind(UnresolvedContext) { Unresolved.Data = unresolved.data(); Unresolved.Length = unresolved.size(); } /// Determine whether this effective Clang context was set. explicit operator bool() const { return getKind() != DeclContext || DC != nullptr; } /// Determine the kind of effective Clang context. Kind getKind() const { return TheKind; } /// Retrieve the declaration context. clang::DeclContext *getAsDeclContext() { return getKind() == DeclContext ? DC : nullptr; } /// Retrieve the typedef declaration. clang::TypedefNameDecl *getTypedefName() const { assert(getKind() == TypedefContext); return Typedef; } /// Retrieve the unresolved context name. StringRef getUnresolvedName() const { assert(getKind() == UnresolvedContext); return StringRef(Unresolved.Data, Unresolved.Length); } }; class SwiftLookupTableReader; class SwiftLookupTableWriter; /// Lookup table major version number. /// const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MAJOR = 1; /// Lookup table minor version number. /// /// When the format changes IN ANY WAY, this number should be incremented. const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 9; // typedef context kind /// A lookup table that maps Swift names to the set of Clang /// declarations with that particular name. /// /// The names of C entities can undergo significant transformations /// when they are mapped into Swift, which makes Clang's name lookup /// mechanisms useless when searching for the Swift name of /// entities. This lookup table provides efficient access to the C /// entities based on their Swift names, and is used by the Clang /// importer to satisfy the Swift compiler's queries. class SwiftLookupTable { public: /// The kind of context in which a name occurs. enum class ContextKind : uint8_t { /// A translation unit. TranslationUnit = 0, /// A tag declaration (struct, enum, union, C++ class). Tag, /// An Objective-C class. ObjCClass, /// An Objective-C protocol. ObjCProtocol, /// A typedef that produces a strong type in Swift. Typedef, }; /// Determine whether the given context requires a name to disambiguate. static bool contextRequiresName(ContextKind kind); /// A single entry referencing either a named declaration or a macro. typedef llvm::PointerUnion SingleEntry; /// A stored version of the context of an entity, which is Clang /// ASTContext-independent. typedef std::pair StoredContext; /// An entry in the table of C entities indexed by full Swift name. struct FullTableEntry { /// The context in which the entities with the given name occur, e.g., /// a class, struct, translation unit, etc. /// is always the canonical DeclContext for the entity. StoredContext Context; /// The set of Clang declarations and macros with this name and in /// this context. /// /// The low bit indicates whether we have a declaration or macro /// (declaration = unset, macro = set) and the second lowest bit /// indicates whether we have a serialization ID (set = DeclID or /// MacroID, as appropriate) vs. a pointer (unset, /// clang::NamedDecl * or clang::MacroInfo *). In the ID case, the /// upper N-2 bits are the ID value; in the pointer case, the /// lower two bits will always be clear due to the alignment of /// the Clang pointers. llvm::SmallVector DeclsOrMacros; }; /// Whether the given entry is a macro entry. static bool isMacroEntry(uintptr_t entry) { return entry & 0x01; } /// Whether the given entry is a declaration entry. static bool isDeclEntry(uintptr_t entry) { return !isMacroEntry(entry); } /// Whether the given entry is a serialization ID. static bool isSerializationIDEntry(uintptr_t entry) { return (entry & 0x02); } /// Whether the given entry is an AST node. static bool isASTNodeEntry(uintptr_t entry) { return !isSerializationIDEntry(entry); } /// Retrieve the serialization ID for an entry. static uint32_t getSerializationID(uintptr_t entry) { assert(isSerializationIDEntry(entry) && "Not a serialization entry"); return entry >> 2; } /// Retrieve the pointer for an entry. static void *getPointerFromEntry(uintptr_t entry) { assert(isASTNodeEntry(entry) && "Not an AST node entry"); const uintptr_t mask = ~static_cast(0x03); return reinterpret_cast(entry & mask); } /// Encode a Clang named declaration as an entry in the table. static uintptr_t encodeEntry(clang::NamedDecl *decl) { auto bits = reinterpret_cast(decl); assert((bits & 0x03) == 0 && "low bits set?"); return bits; } // Encode a Clang macro as an entry in the table. static uintptr_t encodeEntry(clang::MacroInfo *macro) { auto bits = reinterpret_cast(macro); assert((bits & 0x03) == 0 && "low bits set?"); return bits | 0x01; } /// Encode a declaration ID as an entry in the table. static uintptr_t encodeDeclID(clang::serialization::DeclID id) { auto upper = static_cast(id) << 2; assert(upper >> 2 == id); return upper | 0x02; } /// Encode a macro ID as an entry in the table. static uintptr_t encodeMacroID(clang::serialization::MacroID id) { auto upper = static_cast(id) << 2; assert(upper >> 2 == id); return upper | 0x02 | 0x01; } private: /// A table mapping from the base name of Swift entities to all of /// the C entities that have that name, in all contexts. llvm::DenseMap> LookupTable; /// The list of Objective-C categories and extensions. llvm::SmallVector Categories; /// The reader responsible for lazily loading the contents of this table. SwiftLookupTableReader *Reader; friend class SwiftLookupTableReader; friend class SwiftLookupTableWriter; /// Find or create the table entry for the given base name. llvm::DenseMap>::iterator findOrCreate(StringRef baseName); public: explicit SwiftLookupTable(SwiftLookupTableReader *reader) : Reader(reader) { } /// Maps a stored declaration entry to an actual Clang declaration. clang::NamedDecl *mapStoredDecl(uintptr_t &entry); /// Maps a stored macro entry to an actual Clang macro. clang::MacroInfo *mapStoredMacro(uintptr_t &entry); /// Maps a stored entry to an actual Clang AST node. SingleEntry mapStored(uintptr_t &entry); /// Translate a Clang effective context into a context kind and name. llvm::Optional translateContext(EffectiveClangContext context); /// Add an entry to the lookup table. /// /// \param name The Swift name of the entry. /// \param newEntry The Clang declaration or macro. /// \param effectiveContext The effective context in which name lookup occurs. void addEntry(DeclName name, SingleEntry newEntry, EffectiveClangContext effectiveContext); /// Add an Objective-C category or extension to the table. void addCategory(clang::ObjCCategoryDecl *category); private: /// Lookup the set of entities with the given base name. /// /// \param baseName The base name to search for. All results will /// have this base name. /// /// \param searchContext The context in which the resulting set of /// entities should reside. This may be None to indicate that /// all results from all contexts should be produced. SmallVector lookup(StringRef baseName, llvm::Optional searchContext); public: /// Lookup an unresolved context name and resolve it to a Clang /// named declaration. clang::NamedDecl *resolveContext(StringRef unresolvedName); /// Lookup the set of entities with the given base name. /// /// \param baseName The base name to search for. All results will /// have this base name. /// /// \param searchContext The context in which the resulting set of /// entities should reside. This may be None to indicate that /// all results from all contexts should be produced. SmallVector lookup(StringRef baseName, EffectiveClangContext searchContext); /// Retrieve the set of base names that are stored in the lookup table. SmallVector allBaseNames(); /// Lookup Objective-C members with the given base name, regardless /// of context. SmallVector lookupObjCMembers(StringRef baseName); /// Retrieve the set of Objective-C categories and extensions. ArrayRef categories(); /// Deserialize all entries. void deserializeAll(); /// Dump the internal representation of this lookup table. void dump() const; }; /// Module file extension writer for the Swift lookup tables. class SwiftLookupTableWriter : public clang::ModuleFileExtensionWriter { clang::ASTWriter &Writer; std::function PopulateTable; public: SwiftLookupTableWriter( clang::ModuleFileExtension *extension, std::function populateTable, clang::ASTWriter &writer) : ModuleFileExtensionWriter(extension), Writer(writer), PopulateTable(std::move(populateTable)) { } void writeExtensionContents(clang::Sema &sema, llvm::BitstreamWriter &stream) override; }; /// Module file extension reader for the Swift lookup tables. class SwiftLookupTableReader : public clang::ModuleFileExtensionReader { clang::ASTReader &Reader; clang::serialization::ModuleFile &ModuleFile; std::function OnRemove; void *SerializedTable; ArrayRef Categories; SwiftLookupTableReader(clang::ModuleFileExtension *extension, clang::ASTReader &reader, clang::serialization::ModuleFile &moduleFile, std::function onRemove, void *serializedTable, ArrayRef categories) : ModuleFileExtensionReader(extension), Reader(reader), ModuleFile(moduleFile), OnRemove(onRemove), SerializedTable(serializedTable), Categories(categories) { } public: /// Create a new lookup table reader for the given AST reader and stream /// position. static std::unique_ptr create(clang::ModuleFileExtension *extension, clang::ASTReader &reader, clang::serialization::ModuleFile &moduleFile, std::function onRemove, const llvm::BitstreamCursor &stream); ~SwiftLookupTableReader(); /// Retrieve the AST reader associated with this lookup table reader. clang::ASTReader &getASTReader() const { return Reader; } /// Retrieve the module file associated with this lookup table reader. clang::serialization::ModuleFile &getModuleFile() { return ModuleFile; } /// Retrieve the set of base names that are stored in the on-disk hash table. SmallVector getBaseNames(); /// Retrieve the set of entries associated with the given base name. /// /// \returns true if we found anything, false otherwise. bool lookup(StringRef baseName, SmallVectorImpl &entries); /// Retrieve the declaration IDs of the categories. ArrayRef categories() const { return Categories; } }; } #endif // SWIFT_CLANGIMPORTER_SWIFTLOOKUPTABLE_H