mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
405 lines
14 KiB
C++
405 lines
14 KiB
C++
//===--- 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 <functional>
|
|
#include <utility>
|
|
|
|
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<clang::NamedDecl *, clang::MacroInfo *>
|
|
SingleEntry;
|
|
|
|
/// A stored version of the context of an entity, which is Clang
|
|
/// ASTContext-independent.
|
|
typedef std::pair<ContextKind, StringRef> 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<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 list of Objective-C categories and extensions.
|
|
llvm::SmallVector<clang::ObjCCategoryDecl *, 4> 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<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 effective context into a context kind and name.
|
|
llvm::Optional<StoredContext> 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<SingleEntry, 4>
|
|
lookup(StringRef baseName, llvm::Optional<StoredContext> 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<SingleEntry, 4>
|
|
lookup(StringRef baseName, EffectiveClangContext 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);
|
|
|
|
/// Retrieve the set of Objective-C categories and extensions.
|
|
ArrayRef<clang::ObjCCategoryDecl *> 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<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;
|
|
ArrayRef<clang::serialization::DeclID> Categories;
|
|
|
|
SwiftLookupTableReader(clang::ModuleFileExtension *extension,
|
|
clang::ASTReader &reader,
|
|
clang::serialization::ModuleFile &moduleFile,
|
|
std::function<void()> onRemove,
|
|
void *serializedTable,
|
|
ArrayRef<clang::serialization::DeclID> 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<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);
|
|
|
|
/// Retrieve the declaration IDs of the categories.
|
|
ArrayRef<clang::serialization::DeclID> categories() const {
|
|
return Categories;
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
#endif // SWIFT_CLANGIMPORTER_SWIFTLOOKUPTABLE_H
|