blob: e1675ab6810c6d506ceea19b993c382a9782c5aa [file] [log] [blame]
//===--- SwiftLookupTable.h - Swift Lookup Table ----------------*- 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 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/AST/Decl.h"
#include "clang/AST/DeclObjC.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 "llvm/Support/Compiler.h"
#include <functional>
#include <utility>
namespace llvm {
class BitstreamWriter;
}
namespace clang {
class NamedDecl;
class DeclContext;
class MacroInfo;
class ModuleMacro;
class ObjCCategoryDecl;
class TypedefNameDecl;
}
namespace swift {
/// A name from a SwiftLookupTable that has not been deserialized into a
/// DeclBaseName yet.
struct SerializedSwiftName {
/// The kind of the name if it is a special name
DeclBaseName::Kind Kind;
/// The name of the identifier if it is not a special name
StringRef Name;
SerializedSwiftName() : Kind(DeclBaseName::Kind::Normal), Name(StringRef()) {}
explicit SerializedSwiftName(DeclBaseName::Kind Kind)
: Kind(Kind), Name(StringRef()) {}
explicit SerializedSwiftName(StringRef Name)
: Kind(DeclBaseName::Kind::Normal), Name(Name) {}
SerializedSwiftName(DeclBaseName BaseName) {
Kind = BaseName.getKind();
if (BaseName.getKind() == DeclBaseName::Kind::Normal) {
Name = BaseName.getIdentifier().str();
}
}
/// Deserialize the name, adding it to the context's identifier table
DeclBaseName toDeclBaseName(ASTContext &Context) const;
bool empty() const {
return Kind == DeclBaseName::Kind::Normal && Name.empty();
}
/// Return a string representation of the name that can be used for sorting
StringRef userFacingName() const {
switch (Kind) {
case DeclBaseName::Kind::Normal:
return Name;
case DeclBaseName::Kind::Subscript:
return "subscript";
case DeclBaseName::Kind::Constructor:
return "init";
case DeclBaseName::Kind::Destructor:
return "deinit";
}
llvm_unreachable("unhandled kind");
}
bool operator<(SerializedSwiftName RHS) const {
return userFacingName() < RHS.userFacingName();
}
bool operator==(SerializedSwiftName RHS) const {
if (Kind != RHS.Kind)
return false;
if (Kind == DeclBaseName::Kind::Normal) {
assert(RHS.Kind == DeclBaseName::Kind::Normal);
return Name == RHS.Name;
} else {
return true;
}
}
};
} // end namespace swift
namespace llvm {
using swift::SerializedSwiftName;
// Inherit the DenseMapInfo from StringRef but add a few special cases for
// special names
template<> struct DenseMapInfo<SerializedSwiftName> {
static SerializedSwiftName getEmptyKey() {
return SerializedSwiftName(DenseMapInfo<StringRef>::getEmptyKey());
}
static SerializedSwiftName getTombstoneKey() {
return SerializedSwiftName(DenseMapInfo<StringRef>::getTombstoneKey());
}
static unsigned getHashValue(SerializedSwiftName Val) {
if (Val.Kind == swift::DeclBaseName::Kind::Normal) {
return DenseMapInfo<StringRef>::getHashValue(Val.Name);
} else {
return (unsigned)Val.Kind;
}
}
static bool isEqual(SerializedSwiftName LHS, SerializedSwiftName RHS) {
if (LHS.Kind != RHS.Kind)
return false;
if (LHS.Kind == swift::DeclBaseName::Kind::Normal) {
assert(RHS.Kind == swift::DeclBaseName::Kind::Normal);
return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name);
} else {
return LHS.Kind == RHS.Kind;
}
}
};
} // end namespace llvm
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 : uint8_t {
DeclContext,
TypedefContext,
UnresolvedContext, // must be last
};
private:
union {
const clang::DeclContext *DC;
const clang::TypedefNameDecl *Typedef;
struct {
const char *Data;
} Unresolved;
};
/// If KindOrBiasedLength < Kind::UnresolvedContext, this represents a Kind.
/// Otherwise it's (uintptr_t)Kind::UnresolvedContext plus the length of
/// Unresolved.Data.
uintptr_t KindOrBiasedLength;
public:
EffectiveClangContext() : KindOrBiasedLength(DeclContext) {
DC = nullptr;
}
EffectiveClangContext(const clang::DeclContext *dc)
: KindOrBiasedLength(DeclContext) {
assert(dc != nullptr && "use null constructor instead");
if (auto tagDecl = dyn_cast<clang::TagDecl>(dc)) {
DC = tagDecl->getCanonicalDecl();
} else if (auto oiDecl = dyn_cast<clang::ObjCInterfaceDecl>(dc)) {
DC = oiDecl->getCanonicalDecl();
} else if (auto opDecl = dyn_cast<clang::ObjCProtocolDecl>(dc)) {
DC = opDecl->getCanonicalDecl();
} else if (auto omDecl = dyn_cast<clang::ObjCMethodDecl>(dc)) {
DC = omDecl->getCanonicalDecl();
} else if (auto fDecl = dyn_cast<clang::FunctionDecl>(dc)) {
DC = fDecl->getCanonicalDecl();
} else {
assert(isa<clang::TranslationUnitDecl>(dc) ||
isa<clang::ObjCContainerDecl>(dc) &&
"No other kinds of effective Clang contexts");
DC = dc;
}
}
EffectiveClangContext(const clang::TypedefNameDecl *typedefName)
: KindOrBiasedLength(TypedefContext) {
Typedef = typedefName->getCanonicalDecl();
}
EffectiveClangContext(StringRef unresolved)
: KindOrBiasedLength(UnresolvedContext + unresolved.size()) {
Unresolved.Data = unresolved.data();
}
/// 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 {
if (KindOrBiasedLength >= UnresolvedContext)
return UnresolvedContext;
return static_cast<Kind>(KindOrBiasedLength);
}
/// Retrieve the declaration context.
const clang::DeclContext *getAsDeclContext() const {
return getKind() == DeclContext ? DC : nullptr;
}
/// Retrieve the typedef declaration.
const clang::TypedefNameDecl *getTypedefName() const {
assert(getKind() == TypedefContext);
return Typedef;
}
/// Retrieve the unresolved context name.
StringRef getUnresolvedName() const {
assert(getKind() == UnresolvedContext);
return StringRef(Unresolved.Data, KindOrBiasedLength - UnresolvedContext);
}
/// Compares two EffectiveClangContexts without resolving unresolved names.
bool equalsWithoutResolving(const EffectiveClangContext &other) const {
if (getKind() != other.getKind())
return false;
switch (getKind()) {
case DeclContext:
return DC == other.DC;
case TypedefContext:
return Typedef == other.Typedef;
case UnresolvedContext:
return getUnresolvedName() == other.getUnresolvedName();
}
llvm_unreachable("unhandled kind");
}
};
static_assert(sizeof(EffectiveClangContext) <= 2 * sizeof(void *),
"should be small");
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 = 15; // Special names
/// 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.
///
/// Note that values 0 and 1 are reserved for empty and tombstone
/// keys.
enum class ContextKind : uint8_t {
/// A translation unit.
TranslationUnit = 2,
/// 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::PointerUnion3<clang::NamedDecl *, clang::MacroInfo *,
clang::ModuleMacro *>
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
/// {IdentifierID,SubmoduleID}, as appropriate) vs. a pointer (unset,
/// clang::NamedDecl *, clang::MacroInfo *, clang::ModuleMacro *).
/// 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<uint64_t, 2> DeclsOrMacros;
};
/// Whether the given entry is a macro entry.
static bool isMacroEntry(uint64_t entry) { return entry & 0x01; }
/// Whether the given entry is a declaration entry.
static bool isDeclEntry(uint64_t entry) { return !isMacroEntry(entry); }
/// Whether the given entry is a serialization ID.
static bool isSerializationIDEntry(uint64_t entry) { return (entry & 0x02); }
/// Whether the given entry is an AST node.
static bool isASTNodeEntry(uint64_t entry) {
return !isSerializationIDEntry(entry);
}
/// Retrieve the pointer for an entry.
static void *getPointerFromEntry(uint64_t entry) {
assert(isASTNodeEntry(entry) && "Not an AST node entry");
const uint64_t mask = ~static_cast<uint64_t>(0x03);
return reinterpret_cast<void *>(entry & mask);
}
/// Encode a Clang named declaration as an entry in the table.
static uint64_t encodeEntry(clang::NamedDecl *decl) {
assert(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 uint64_t encodeEntry(clang::MacroInfo *macro) {
assert(macro);
auto bits = reinterpret_cast<uintptr_t>(macro);
assert((bits & 0x03) == 0 && "low bits set?");
return bits | 0x01;
}
// Encode a Clang macro as an entry in the table.
static uint64_t encodeEntry(clang::ModuleMacro *macro) {
assert(macro);
auto bits = reinterpret_cast<uintptr_t>(macro);
assert((bits & 0x03) == 0 && "low bits set?");
return bits | 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<SerializedSwiftName, SmallVector<FullTableEntry, 2>>
LookupTable;
/// The list of Objective-C categories and extensions.
llvm::SmallVector<clang::ObjCCategoryDecl *, 4> Categories;
/// A mapping from stored contexts to the set of global declarations that
/// are mapped to members within that context.
///
/// The values use the same representation as
/// FullTableEntry::DeclsOrMacros.
llvm::DenseMap<StoredContext, SmallVector<uint64_t, 2>> GlobalsAsMembers;
/// The reader responsible for lazily loading the contents of this table.
SwiftLookupTableReader *Reader;
/// Entries whose effective contexts could not be resolved, and
/// therefore will need to be added later.
SmallVector<std::tuple<DeclName, SingleEntry, EffectiveClangContext>, 4>
UnresolvedEntries;
friend class SwiftLookupTableReader;
friend class SwiftLookupTableWriter;
/// Find or create the table entry for the given base name.
llvm::DenseMap<SerializedSwiftName, SmallVector<FullTableEntry, 2>>::iterator
findOrCreate(SerializedSwiftName baseName);
/// Add the given entry to the list of entries, if it's not already
/// present.
///
/// \returns true if the entry was added, false otherwise.
bool addLocalEntry(SingleEntry newEntry, SmallVectorImpl<uint64_t> &entries);
public:
explicit SwiftLookupTable(SwiftLookupTableReader *reader) : Reader(reader) { }
/// Maps a stored declaration entry to an actual Clang declaration.
clang::NamedDecl *mapStoredDecl(uint64_t &entry);
/// Maps a stored macro entry to an actual Clang macro.
SingleEntry mapStoredMacro(uint64_t &entry, bool assumeModule = false);
/// Maps a stored entry to an actual Clang AST node.
SingleEntry mapStored(uint64_t &entry, bool assumeModule = false);
/// Translate a Clang DeclContext into a context kind and name.
static llvm::Optional<StoredContext> translateDeclContext(
const clang::DeclContext *dc);
/// 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);
/// Resolve any unresolved entries.
///
/// \param unresolved Will be populated with the list of entries
/// that could not be resolved.
///
/// \returns true if any remaining entries could not be resolved,
/// and false otherwise.
bool resolveUnresolvedEntries(SmallVectorImpl<SingleEntry> &unresolved);
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(SerializedSwiftName baseName,
llvm::Optional<StoredContext> searchContext);
/// Retrieve the set of global declarations that are going to be
/// imported as members into the given context.
SmallVector<SingleEntry, 4> lookupGlobalsAsMembers(StoredContext context);
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(SerializedSwiftName baseName,
EffectiveClangContext searchContext);
/// Retrieve the set of base names that are stored in the lookup table.
SmallVector<SerializedSwiftName, 4> allBaseNames();
/// Lookup Objective-C members with the given base name, regardless
/// of context.
SmallVector<clang::NamedDecl *, 4>
lookupObjCMembers(SerializedSwiftName baseName);
/// Retrieve the set of Objective-C categories and extensions.
ArrayRef<clang::ObjCCategoryDecl *> categories();
/// Retrieve the set of global declarations that are going to be
/// imported as members into the given context.
SmallVector<SingleEntry, 4>
lookupGlobalsAsMembers(EffectiveClangContext context);
/// Retrieve the set of global declarations that are going to be
/// imported as members.
SmallVector<SingleEntry, 4> allGlobalsAsMembers();
/// Deserialize all entries.
void deserializeAll();
/// Dump the internal representation of this lookup table.
void dump() const;
};
namespace importer {
class NameImporter;
/// Add the given named declaration as an entry to the given Swift name
/// lookup table, including any of its child entries.
void addEntryToLookupTable(SwiftLookupTable &table, clang::NamedDecl *named,
NameImporter &);
/// Add the macros from the given Clang preprocessor to the given
/// Swift name lookup table.
void addMacrosToLookupTable(SwiftLookupTable &table, NameImporter &);
/// Finalize a lookup table, handling any as-yet-unresolved entries
/// and emitting diagnostics if necessary.
void finalizeLookupTable(SwiftLookupTable &table, NameImporter &);
}
}
namespace llvm {
template <> struct DenseMapInfo<swift::SwiftLookupTable::ContextKind> {
typedef swift::SwiftLookupTable::ContextKind ContextKind;
static ContextKind getEmptyKey() {
return static_cast<ContextKind>(0);
}
static ContextKind getTombstoneKey() {
return static_cast<ContextKind>(1);
}
static unsigned getHashValue(ContextKind kind) {
return static_cast<unsigned>(kind);
}
static bool isEqual(ContextKind lhs, ContextKind rhs) {
return lhs == rhs;
}
};
}
#endif // SWIFT_CLANGIMPORTER_SWIFTLOOKUPTABLE_H