| //===--- SwiftLookupTable.h - Swift Lookup Table ----------------*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2015 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 <functional> |
| #include <utility> |
| |
| namespace llvm { |
| class BitstreamWriter; |
| } |
| |
| namespace clang { |
| class NamedDecl; |
| class DeclContext; |
| class MacroInfo; |
| } |
| |
| namespace swift { |
| |
| class SwiftLookupTableReader; |
| class SwiftLookupTableWriter; |
| |
| /// Lookup table major version number. |
| /// |
| const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MAJOR = 1; |
| |
| /// Lookup table major version number. |
| /// |
| /// When the format changes IN ANY WAY, this number should be incremented. |
| const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 1; |
| |
| /// 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, |
| }; |
| |
| /// 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<clang::NamedDecl *, clang::MacroInfo *> SingleEntry; |
| |
| /// 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. |
| std::pair<ContextKind, StringRef> 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<uintptr_t, 2> 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<uintptr_t>(0x03); |
| return reinterpret_cast<void *>(entry & mask); |
| } |
| |
| /// Encode a Clang named declaration as an entry in the table. |
| static uintptr_t encodeEntry(clang::NamedDecl *decl) { |
| auto bits = reinterpret_cast<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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<StringRef, SmallVector<FullTableEntry, 2>> LookupTable; |
| |
| /// 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<StringRef, SmallVector<FullTableEntry, 2>>::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 DeclContext into a context kind and name. |
| llvm::Optional<std::pair<ContextKind, StringRef>> |
| translateContext(clang::DeclContext *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, |
| clang::DeclContext *effectiveContext); |
| |
| /// 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 null to indicate that |
| /// all results from all contexts should be produced. |
| SmallVector<SingleEntry, 4> |
| lookup(StringRef baseName, clang::DeclContext *searchContext); |
| |
| /// Retrieve the set of base names that are stored in the lookup table. |
| SmallVector<StringRef, 4> allBaseNames(); |
| |
| /// Lookup Objective-C members with the given base name, regardless |
| /// of context. |
| SmallVector<clang::NamedDecl *, 4> lookupObjCMembers(StringRef baseName); |
| |
| /// 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<void(clang::Sema &, SwiftLookupTable &)> PopulateTable; |
| |
| public: |
| SwiftLookupTableWriter( |
| clang::ModuleFileExtension *extension, |
| std::function<void(clang::Sema &, SwiftLookupTable &)> 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<void()> OnRemove; |
| |
| void *SerializedTable; |
| |
| SwiftLookupTableReader(clang::ModuleFileExtension *extension, |
| clang::ASTReader &reader, |
| clang::serialization::ModuleFile &moduleFile, |
| std::function<void()> onRemove, |
| void *serializedTable) |
| : ModuleFileExtensionReader(extension), Reader(reader), |
| ModuleFile(moduleFile), OnRemove(onRemove), |
| SerializedTable(serializedTable) { } |
| |
| public: |
| /// Create a new lookup table reader for the given AST reader and stream |
| /// position. |
| static std::unique_ptr<SwiftLookupTableReader> |
| create(clang::ModuleFileExtension *extension, clang::ASTReader &reader, |
| clang::serialization::ModuleFile &moduleFile, |
| std::function<void()> 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<StringRef, 4> 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<SwiftLookupTable::FullTableEntry> &entries); |
| }; |
| |
| } |
| |
| #endif // SWIFT_CLANGIMPORTER_SWIFTLOOKUPTABLE_H |