Files
swift-mirror/include/swift/AST/Identifier.h
Holly Borla dab3b64c99 [ConstraintSystem] Implement basic type checking for pack expressions.
During prechecking, postfix '...' expressions are rewritten to pack
expansion expressions if the operand contains pack references. References
to packs are replaced with opaque values, and the pack expansion stores
the opaque value bindings to decl refs.
2022-10-22 13:41:48 -07:00

1029 lines
32 KiB
C++

//===--- Identifier.h - Uniqued Identifier ----------------------*- 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 Identifier interface.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_IDENTIFIER_H
#define SWIFT_AST_IDENTIFIER_H
#include "swift/Basic/EditorPlaceholder.h"
#include "swift/Basic/Debug.h"
#include "swift/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/TrailingObjects.h"
namespace llvm {
class raw_ostream;
}
namespace swift {
class ASTContext;
class ParameterList;
/// DeclRefKind - The kind of reference to an identifier.
enum class DeclRefKind {
/// An ordinary reference to an identifier, e.g. 'foo'.
Ordinary,
/// A reference to an identifier as a binary operator, e.g. '+' in 'a+b'.
BinaryOperator,
/// A reference to an identifier as a postfix unary operator, e.g. '++' in
/// 'a++'.
PostfixOperator,
/// A reference to an identifier as a prefix unary operator, e.g. '--' in
/// '--a'.
PrefixOperator
};
/// Identifier - This is an instance of a uniqued identifier created by
/// ASTContext. It just wraps a nul-terminated "const char*".
class Identifier {
friend class ASTContext;
friend class DeclBaseName;
const char *Pointer;
public:
enum : size_t {
NumLowBitsAvailable = 3,
RequiredAlignment = 1 << NumLowBitsAvailable,
SpareBitMask = ((intptr_t)1 << NumLowBitsAvailable) - 1
};
private:
/// Constructor, only accessible by ASTContext, which handles the uniquing.
explicit Identifier(const char *Ptr) : Pointer(Ptr) {
assert(((uintptr_t)Ptr & SpareBitMask) == 0
&& "Identifier pointer does not use any spare bits");
}
/// A type with the alignment expected of a valid \c Identifier::Pointer .
struct alignas(uint64_t) Aligner {};
static_assert(alignof(Aligner) >= RequiredAlignment,
"Identifier table will provide enough spare bits");
public:
explicit Identifier() : Pointer(nullptr) {}
const char *get() const { return Pointer; }
StringRef str() const { return Pointer; }
explicit operator std::string() const { return std::string(Pointer); }
unsigned getLength() const {
assert(Pointer != nullptr && "Tried getting length of empty identifier");
return ::strlen(Pointer);
}
bool empty() const { return Pointer == nullptr; }
LLVM_ATTRIBUTE_USED bool is(StringRef string) const {
return str().equals(string);
}
/// isOperator - Return true if this identifier is an operator, false if it is
/// a normal identifier.
/// FIXME: We should maybe cache this.
bool isOperator() const {
if (empty())
return false;
if (isEditorPlaceholder())
return false;
if ((unsigned char)Pointer[0] < 0x80)
return isOperatorStartCodePoint((unsigned char)Pointer[0]);
// Handle the high unicode case out of line.
return isOperatorSlow();
}
bool isArithmeticOperator() const {
return is("+") || is("-") || is("*") || is("/") || is("%");
}
// Returns whether this is a standard comparison operator,
// such as '==', '>=' or '!=='.
bool isStandardComparisonOperator() const {
return is("==") || is("!=") || is("===") || is("!==") || is("<") ||
is(">") || is("<=") || is(">=");
}
bool isNilCoalescingOperator() const {
return is("??");
}
bool isExpansionOperator() const {
return is("...");
}
/// isOperatorStartCodePoint - Return true if the specified code point is a
/// valid start of an operator.
static bool isOperatorStartCodePoint(uint32_t C) {
// ASCII operator chars.
static const char OpChars[] = "/=-+*%<>!&|^~.?";
if (C < 0x80)
return memchr(OpChars, C, sizeof(OpChars) - 1) != 0;
// Unicode math, symbol, arrow, dingbat, and line/box drawing chars.
return (C >= 0x00A1 && C <= 0x00A7)
|| C == 0x00A9 || C == 0x00AB || C == 0x00AC || C == 0x00AE
|| C == 0x00B0 || C == 0x00B1 || C == 0x00B6 || C == 0x00BB
|| C == 0x00BF || C == 0x00D7 || C == 0x00F7
|| C == 0x2016 || C == 0x2017 || (C >= 0x2020 && C <= 0x2027)
|| (C >= 0x2030 && C <= 0x203E) || (C >= 0x2041 && C <= 0x2053)
|| (C >= 0x2055 && C <= 0x205E) || (C >= 0x2190 && C <= 0x23FF)
|| (C >= 0x2500 && C <= 0x2775) || (C >= 0x2794 && C <= 0x2BFF)
|| (C >= 0x2E00 && C <= 0x2E7F) || (C >= 0x3001 && C <= 0x3003)
|| (C >= 0x3008 && C <= 0x3030);
}
/// isOperatorContinuationCodePoint - Return true if the specified code point
/// is a valid operator code point.
static bool isOperatorContinuationCodePoint(uint32_t C) {
if (isOperatorStartCodePoint(C))
return true;
// Unicode combining characters and variation selectors.
return (C >= 0x0300 && C <= 0x036F)
|| (C >= 0x1DC0 && C <= 0x1DFF)
|| (C >= 0x20D0 && C <= 0x20FF)
|| (C >= 0xFE00 && C <= 0xFE0F)
|| (C >= 0xFE20 && C <= 0xFE2F)
|| (C >= 0xE0100 && C <= 0xE01EF);
}
static bool isEditorPlaceholder(StringRef name) {
return swift::isEditorPlaceholder(name);
}
bool isEditorPlaceholder() const {
return !empty() && isEditorPlaceholder(str());
}
bool hasDollarPrefix() const {
return str().startswith("$") && !(getLength() == 1);
}
const void *getAsOpaquePointer() const {
return static_cast<const void *>(Pointer);
}
static Identifier getFromOpaquePointer(void *P) {
return Identifier((const char*)P);
}
/// Compare two identifiers, producing -1 if \c *this comes before \c other,
/// 1 if \c *this comes after \c other, and 0 if they are equal.
///
/// Null identifiers come after all other identifiers.
int compare(Identifier other) const;
friend llvm::hash_code hash_value(Identifier ident) {
return llvm::hash_value(ident.getAsOpaquePointer());
}
bool operator==(Identifier RHS) const { return Pointer == RHS.Pointer; }
bool operator!=(Identifier RHS) const { return !(*this==RHS); }
bool operator<(Identifier RHS) const { return Pointer < RHS.Pointer; }
static Identifier getEmptyKey() {
uintptr_t Val = static_cast<uintptr_t>(-1);
Val <<= NumLowBitsAvailable;
return Identifier((const char*)Val);
}
static Identifier getTombstoneKey() {
uintptr_t Val = static_cast<uintptr_t>(-2);
Val <<= NumLowBitsAvailable;
return Identifier((const char*)Val);
}
private:
bool isOperatorSlow() const;
};
class DeclName;
class DeclNameRef;
class ObjCSelector;
} // end namespace swift
namespace llvm {
raw_ostream &operator<<(raw_ostream &OS, swift::Identifier I);
raw_ostream &operator<<(raw_ostream &OS, swift::DeclName I);
raw_ostream &operator<<(raw_ostream &OS, swift::DeclNameRef I);
raw_ostream &operator<<(raw_ostream &OS, swift::ObjCSelector S);
// Identifiers hash just like pointers.
template<> struct DenseMapInfo<swift::Identifier> {
static swift::Identifier getEmptyKey() {
return swift::Identifier::getEmptyKey();
}
static swift::Identifier getTombstoneKey() {
return swift::Identifier::getTombstoneKey();
}
static unsigned getHashValue(swift::Identifier Val) {
return DenseMapInfo<const void*>::getHashValue(Val.get());
}
static bool isEqual(swift::Identifier LHS, swift::Identifier RHS) {
return LHS == RHS;
}
};
// An Identifier is "pointer like".
template<typename T> struct PointerLikeTypeTraits;
template<>
struct PointerLikeTypeTraits<swift::Identifier> {
public:
static inline void *getAsVoidPointer(swift::Identifier I) {
return const_cast<void *>(I.getAsOpaquePointer());
}
static inline swift::Identifier getFromVoidPointer(void *P) {
return swift::Identifier::getFromOpaquePointer(P);
}
enum { NumLowBitsAvailable = swift::Identifier::NumLowBitsAvailable };
};
} // end namespace llvm
namespace swift {
/// Wrapper that may either be an Identifier or a special name
/// (e.g. for subscripts)
class DeclBaseName {
public:
enum class Kind: uint8_t {
Normal,
Subscript,
Constructor,
Destructor
};
private:
/// In a special DeclName representing a subscript, this opaque pointer
/// is used as the data of the base name identifier.
/// This is an implementation detail that should never leak outside of
/// DeclName.
static const Identifier::Aligner SubscriptIdentifierData;
/// As above, for special constructor DeclNames.
static const Identifier::Aligner ConstructorIdentifierData;
/// As above, for special destructor DeclNames.
static const Identifier::Aligner DestructorIdentifierData;
Identifier Ident;
public:
DeclBaseName() : DeclBaseName(Identifier()) {}
DeclBaseName(Identifier I) : Ident(I) {}
static DeclBaseName createSubscript() {
return DeclBaseName(Identifier((const char *)&SubscriptIdentifierData));
}
static DeclBaseName createConstructor() {
return DeclBaseName(Identifier((const char *)&ConstructorIdentifierData));
}
static DeclBaseName createDestructor() {
return DeclBaseName(Identifier((const char *)&DestructorIdentifierData));
}
Kind getKind() const {
if (Ident.get() == (const char *)&SubscriptIdentifierData) {
return Kind::Subscript;
} else if (Ident.get() == (const char *)&ConstructorIdentifierData) {
return Kind::Constructor;
} else if (Ident.get() == (const char *)&DestructorIdentifierData) {
return Kind::Destructor;
} else {
return Kind::Normal;
}
}
bool isSpecial() const { return getKind() != Kind::Normal; }
bool isSubscript() const { return getKind() == Kind::Subscript; }
/// Return the identifier backing the name. Assumes that the name is not
/// special.
Identifier getIdentifier() const {
assert(!isSpecial() && "Cannot retrieve identifier from special names");
return Ident;
}
bool empty() const { return !isSpecial() && getIdentifier().empty(); }
bool isOperator() const {
return !isSpecial() && getIdentifier().isOperator();
}
bool isEditorPlaceholder() const {
return !isSpecial() && getIdentifier().isEditorPlaceholder();
}
bool hasDollarPrefix() const {
return getIdentifier().hasDollarPrefix();
}
/// A representation of the name to be displayed to users. May be ambiguous
/// between identifiers and special names.
StringRef userFacingName() const {
if (empty())
return "_";
switch (getKind()) {
case Kind::Normal:
return getIdentifier().str();
case Kind::Subscript:
return "subscript";
case Kind::Constructor:
return "init";
case Kind::Destructor:
return "deinit";
}
llvm_unreachable("unhandled kind");
}
int compare(DeclBaseName other) const {
return userFacingName().compare(other.userFacingName());
}
bool operator==(StringRef Str) const {
return !isSpecial() && getIdentifier().is(Str);
}
bool operator!=(StringRef Str) const { return !(*this == Str); }
bool operator==(DeclBaseName RHS) const { return Ident == RHS.Ident; }
bool operator!=(DeclBaseName RHS) const { return !(*this == RHS); }
bool operator<(DeclBaseName RHS) const {
return Ident.get() < RHS.Ident.get();
}
const void *getAsOpaquePointer() const { return Ident.get(); }
static DeclBaseName getFromOpaquePointer(void *P) {
return Identifier::getFromOpaquePointer(P);
}
};
} // end namespace swift
namespace llvm {
raw_ostream &operator<<(raw_ostream &OS, swift::DeclBaseName D);
// DeclBaseNames hash just like pointers.
template<> struct DenseMapInfo<swift::DeclBaseName> {
static swift::DeclBaseName getEmptyKey() {
return swift::Identifier::getEmptyKey();
}
static swift::DeclBaseName getTombstoneKey() {
return swift::Identifier::getTombstoneKey();
}
static unsigned getHashValue(swift::DeclBaseName Val) {
return DenseMapInfo<const void *>::getHashValue(Val.getAsOpaquePointer());
}
static bool isEqual(swift::DeclBaseName LHS, swift::DeclBaseName RHS) {
return LHS == RHS;
}
};
// A DeclBaseName is "pointer like".
template <typename T> struct PointerLikeTypeTraits;
template <> struct PointerLikeTypeTraits<swift::DeclBaseName> {
public:
static inline void *getAsVoidPointer(swift::DeclBaseName D) {
return const_cast<void *>(D.getAsOpaquePointer());
}
static inline swift::DeclBaseName getFromVoidPointer(void *P) {
return swift::DeclBaseName::getFromOpaquePointer(P);
}
enum { NumLowBitsAvailable = PointerLikeTypeTraits<swift::Identifier>::NumLowBitsAvailable };
};
} // end namespace llvm
namespace swift {
/// A declaration name, which may comprise one or more identifier pieces.
class DeclName {
friend class ASTContext;
/// Represents a compound declaration name.
struct alignas(Identifier) CompoundDeclName final : llvm::FoldingSetNode,
private llvm::TrailingObjects<CompoundDeclName, Identifier> {
friend TrailingObjects;
friend class DeclName;
DeclBaseName BaseName;
size_t NumArgs;
explicit CompoundDeclName(DeclBaseName BaseName, size_t NumArgs)
: BaseName(BaseName), NumArgs(NumArgs) { }
ArrayRef<Identifier> getArgumentNames() const {
return {getTrailingObjects<Identifier>(), NumArgs};
}
MutableArrayRef<Identifier> getArgumentNames() {
return {getTrailingObjects<Identifier>(), NumArgs};
}
/// Uniquing for the ASTContext.
static void Profile(llvm::FoldingSetNodeID &id, DeclBaseName baseName,
ArrayRef<Identifier> argumentNames);
void Profile(llvm::FoldingSetNodeID &id) {
Profile(id, BaseName, getArgumentNames());
}
};
/// Either a single identifier piece stored inline, or a reference to a
/// compound declaration name.
llvm::PointerUnion<DeclBaseName, CompoundDeclName *> BaseNameOrCompound;
explicit DeclName(void *Opaque)
: BaseNameOrCompound(decltype(BaseNameOrCompound)::getFromOpaqueValue(Opaque))
{}
void initialize(ASTContext &C, DeclBaseName baseName,
ArrayRef<Identifier> argumentNames);
public:
/// Build a null name.
DeclName() : BaseNameOrCompound(DeclBaseName()) {}
/// Build a simple value name with one component.
/*implicit*/ DeclName(DeclBaseName simpleName)
: BaseNameOrCompound(simpleName) {}
/*implicit*/ DeclName(Identifier simpleName)
: DeclName(DeclBaseName(simpleName)) {}
/// Build a compound value name given a base name and a set of argument names.
DeclName(ASTContext &C, DeclBaseName baseName,
ArrayRef<Identifier> argumentNames) {
initialize(C, baseName, argumentNames);
}
/// Build a compound value name given a base name and a set of argument names
/// extracted from a parameter list.
DeclName(ASTContext &C, DeclBaseName baseName, ParameterList *paramList);
/// Retrieve the 'base' name, i.e., the name that follows the introducer,
/// such as the 'foo' in 'func foo(x:Int, y:Int)' or the 'bar' in
/// 'var bar: Int'.
DeclBaseName getBaseName() const {
if (auto compound = BaseNameOrCompound.dyn_cast<CompoundDeclName*>())
return compound->BaseName;
return BaseNameOrCompound.get<DeclBaseName>();
}
/// Assert that the base name is not special and return its identifier.
Identifier getBaseIdentifier() const {
auto baseName = getBaseName();
assert(!baseName.isSpecial() &&
"Can't retrieve the identifier of a special base name");
return baseName.getIdentifier();
}
/// Retrieve the names of the arguments, if there are any.
ArrayRef<Identifier> getArgumentNames() const {
if (auto compound = BaseNameOrCompound.dyn_cast<CompoundDeclName*>())
return compound->getArgumentNames();
return { };
}
bool isSpecial() const { return getBaseName().isSpecial(); }
explicit operator bool() const {
if (BaseNameOrCompound.dyn_cast<CompoundDeclName*>())
return true;
return !BaseNameOrCompound.get<DeclBaseName>().empty();
}
/// True if this is a simple one-component name.
bool isSimpleName() const {
return BaseNameOrCompound.is<DeclBaseName>();
}
/// True if this is a compound name.
bool isCompoundName() const {
return !isSimpleName();
}
/// True if this name is a simple one-component name identical to the
/// given identifier.
bool isSimpleName(DeclBaseName name) const {
return isSimpleName() && getBaseName() == name;
}
/// True if this name is a simple one-component name equal to the
/// given string.
bool isSimpleName(StringRef name) const {
return isSimpleName() && getBaseName() == name;
}
/// True if this name is a compound name equal to the given base name and
/// argument names.
bool isCompoundName(DeclBaseName base, ArrayRef<StringRef> args) const;
/// True if this name is a compound name equal to the given normal
/// base name and argument names.
bool isCompoundName(StringRef base, ArrayRef<StringRef> args) const;
/// True if this name is an operator.
bool isOperator() const {
return getBaseName().isOperator();
}
/// True if this name should be found by a decl ref or member ref under the
/// name specified by 'refName'.
///
/// We currently match compound names either when their first component
/// matches a simple name lookup or when the full compound name matches.
bool matchesRef(DeclName refName) const {
// Identical names always match.
if (BaseNameOrCompound == refName.BaseNameOrCompound)
return true;
// If the reference is a simple name, try simple name matching.
if (refName.isSimpleName())
return refName.getBaseName() == getBaseName();
// The names don't match.
return false;
}
/// Add a DeclName to a lookup table so that it can be found by its simple
/// name or its compound name.
template<typename LookupTable, typename Element>
void addToLookupTable(LookupTable &table, const Element &elt) {
table[*this].push_back(elt);
if (!isSimpleName()) {
table[getBaseName()].push_back(elt);
}
}
/// Compare two declaration names, producing -1 if \c *this comes before
/// \c other, 1 if \c *this comes after \c other, and 0 if they are equal.
///
/// Null declaration names come after all other declaration names.
int compare(DeclName other) const;
friend bool operator==(DeclName lhs, DeclName rhs) {
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
}
friend bool operator!=(DeclName lhs, DeclName rhs) {
return !(lhs == rhs);
}
friend llvm::hash_code hash_value(DeclName name) {
using llvm::hash_value;
return hash_value(name.getOpaqueValue());
}
friend bool operator<(DeclName lhs, DeclName rhs) {
return lhs.compare(rhs) < 0;
}
friend bool operator<=(DeclName lhs, DeclName rhs) {
return lhs.compare(rhs) <= 0;
}
friend bool operator>(DeclName lhs, DeclName rhs) {
return lhs.compare(rhs) > 0;
}
friend bool operator>=(DeclName lhs, DeclName rhs) {
return lhs.compare(rhs) >= 0;
}
void *getOpaqueValue() const { return BaseNameOrCompound.getOpaqueValue(); }
static DeclName getFromOpaqueValue(void *p) { return DeclName(p); }
/// Get a string representation of the name,
///
/// \param scratch Scratch space to use.
StringRef getString(llvm::SmallVectorImpl<char> &scratch,
bool skipEmptyArgumentNames = false) const;
/// Print the representation of this declaration name to the given
/// stream.
///
/// \param skipEmptyArgumentNames When true, don't print the argument labels
/// if they are all empty.
llvm::raw_ostream &print(llvm::raw_ostream &os,
bool skipEmptyArgumentNames = false) const;
/// Print a "pretty" representation of this declaration name to the given
/// stream.
///
/// This is the name used for diagnostics; it is not necessarily the
/// fully-specified name that would be written in the source.
llvm::raw_ostream &printPretty(llvm::raw_ostream &os) const;
/// Dump this name to standard error.
SWIFT_DEBUG_DUMP;
};
void simple_display(llvm::raw_ostream &out, DeclName name);
/// An in-source reference to another declaration, including qualification
/// information.
class DeclNameRef {
DeclName FullName;
public:
static DeclNameRef createSubscript();
static DeclNameRef createConstructor();
DeclNameRef() : FullName() { }
void *getOpaqueValue() const { return FullName.getOpaqueValue(); }
static DeclNameRef getFromOpaqueValue(void *p);
explicit DeclNameRef(DeclName FullName)
: FullName(FullName) { }
explicit DeclNameRef(DeclBaseName BaseName)
: FullName(BaseName) { }
explicit DeclNameRef(Identifier BaseName)
: FullName(BaseName) { }
/// The name of the declaration being referenced.
DeclName getFullName() const {
return FullName;
}
DeclName &getFullName() {
return FullName;
}
/// The base name of the declaration being referenced.
DeclBaseName getBaseName() const {
return FullName.getBaseName();
}
Identifier getBaseIdentifier() const {
return FullName.getBaseIdentifier();
}
ArrayRef<Identifier> getArgumentNames() const {
return FullName.getArgumentNames();
}
bool isSimpleName() const {
return FullName.isSimpleName();
}
bool isSimpleName(DeclBaseName name) const {
return FullName.isSimpleName(name);
}
bool isSimpleName(StringRef name) const {
return FullName.isSimpleName(name);
}
bool isSpecial() const {
return FullName.isSpecial();
}
bool isOperator() const {
return FullName.isOperator();
}
bool isCompoundName() const {
return FullName.isCompoundName();
}
explicit operator bool() const {
return (bool)FullName;
}
/// Compare two declaration names, producing -1 if \c *this comes before
/// \c other, 1 if \c *this comes after \c other, and 0 if they are equal.
///
/// Null declaration names come after all other declaration names.
int compare(DeclNameRef other) const {
return getFullName().compare(other.getFullName());
}
friend bool operator==(DeclNameRef lhs, DeclNameRef rhs) {
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
}
friend bool operator!=(DeclNameRef lhs, DeclNameRef rhs) {
return !(lhs == rhs);
}
friend llvm::hash_code hash_value(DeclNameRef name) {
using llvm::hash_value;
return hash_value(name.getFullName().getOpaqueValue());
}
friend bool operator<(DeclNameRef lhs, DeclNameRef rhs) {
return lhs.compare(rhs) < 0;
}
friend bool operator<=(DeclNameRef lhs, DeclNameRef rhs) {
return lhs.compare(rhs) <= 0;
}
friend bool operator>(DeclNameRef lhs, DeclNameRef rhs) {
return lhs.compare(rhs) > 0;
}
friend bool operator>=(DeclNameRef lhs, DeclNameRef rhs) {
return lhs.compare(rhs) >= 0;
}
DeclNameRef withoutArgumentLabels() const;
DeclNameRef withArgumentLabels(ASTContext &C,
ArrayRef<Identifier> argumentNames) const;
/// Get a string representation of the name,
///
/// \param scratch Scratch space to use.
StringRef getString(llvm::SmallVectorImpl<char> &scratch,
bool skipEmptyArgumentNames = false) const;
/// Print the representation of this declaration name to the given
/// stream.
///
/// \param skipEmptyArgumentNames When true, don't print the argument labels
/// if they are all empty.
llvm::raw_ostream &print(llvm::raw_ostream &os,
bool skipEmptyArgumentNames = false) const;
/// Print a "pretty" representation of this declaration name to the given
/// stream.
///
/// This is the name used for diagnostics; it is not necessarily the
/// fully-specified name that would be written in the source.
llvm::raw_ostream &printPretty(llvm::raw_ostream &os) const;
/// Dump this name to standard error.
SWIFT_DEBUG_DUMP;
};
inline DeclNameRef DeclNameRef::getFromOpaqueValue(void *p) {
return DeclNameRef(DeclName::getFromOpaqueValue(p));
}
inline DeclNameRef DeclNameRef::withoutArgumentLabels() const {
return DeclNameRef(getBaseName());
}
inline DeclNameRef DeclNameRef::withArgumentLabels(
ASTContext &C, ArrayRef<Identifier> argumentNames) const {
return DeclNameRef(DeclName(C, getBaseName(), argumentNames));
}
inline DeclNameRef DeclNameRef::createSubscript() {
return DeclNameRef(DeclBaseName::createSubscript());
}
inline DeclNameRef DeclNameRef::createConstructor() {
return DeclNameRef(DeclBaseName::createConstructor());
}
void simple_display(llvm::raw_ostream &out, DeclNameRef name);
enum class ObjCSelectorFamily : unsigned {
None,
#define OBJC_SELECTOR_FAMILY(LABEL, PREFIX) LABEL,
#include "swift/AST/ObjCSelectorFamily.def"
};
/// Represents an Objective-C selector.
class ObjCSelector {
/// The storage for an Objective-C selector.
///
/// A zero-argument selector is represented as simple name.
/// A selector with N arguments is represented as a compound name with
/// N arguments, where the simple name is a placeholder.
DeclName Storage;
explicit ObjCSelector(DeclName storage) : Storage(storage) { }
friend struct llvm::DenseMapInfo<ObjCSelector>;
public:
/// Form a selector with the given number of arguments and the given selector
/// pieces.
ObjCSelector(ASTContext &ctx, unsigned numArgs, ArrayRef<Identifier> pieces);
/// Construct an invalid ObjCSelector.
ObjCSelector() : Storage() {}
/// Split \p string into selector pieces on colons to create an ObjCSelector.
///
/// This should not be used to parse selectors written directly in Swift
/// source code (e.g. the argument of an @objc attribute). Use the
/// parser for that.
static llvm::Optional<ObjCSelector> parse(ASTContext &ctx, StringRef string);
/// Convert to true if the decl name is valid.
explicit operator bool() const { return (bool)Storage; }
/// Determine the number of arguments in the selector.
///
/// When this is zero, the number of selector pieces will be one. Otherwise,
/// it equals the number of selector pieces.
unsigned getNumArgs() const {
if (Storage.isSimpleName()) {
return 0;
}
return Storage.getArgumentNames().size();
}
/// Determine the number of selector pieces in the selector.
///
/// When this is one, the number of arguments may either be zero or one.
/// Otherwise, it equals the number of arguments.
unsigned getNumSelectorPieces() const {
return getSelectorPieces().size();
}
/// Retrieve the pieces in this selector.
ArrayRef<Identifier> getSelectorPieces() const {
if (Storage.isSimpleName()) {
return { reinterpret_cast<const Identifier*>(&Storage), 1 };
}
return Storage.getArgumentNames();
}
/// Asserts that this is a nullary selector and returns the single identifier.
Identifier getSimpleName() const {
assert(Storage.isSimpleName() && "not a nullary selector");
return Storage.getBaseIdentifier();
}
/// Get a string representation of the selector.
///
/// \param scratch Scratch space to use.
StringRef getString(llvm::SmallVectorImpl<char> &scratch) const;
ObjCSelectorFamily getSelectorFamily() const;
void *getOpaqueValue() const { return Storage.getOpaqueValue(); }
static ObjCSelector getFromOpaqueValue(void *p) {
return ObjCSelector(DeclName::getFromOpaqueValue(p));
}
/// Dump this selector to standard error.
SWIFT_DEBUG_DUMP;
/// Compare two Objective-C selectors, producing -1 if \c *this comes before
/// \c other, 1 if \c *this comes after \c other, and 0 if they are equal.
int compare(ObjCSelector other) const {
return Storage.compare(other.Storage);
}
friend bool operator==(ObjCSelector lhs, ObjCSelector rhs) {
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
}
friend bool operator!=(ObjCSelector lhs, ObjCSelector rhs) {
return !(lhs == rhs);
}
friend bool operator<(ObjCSelector lhs, ObjCSelector rhs) {
return lhs.compare(rhs) < 0;
}
friend bool operator<=(ObjCSelector lhs, ObjCSelector rhs) {
return lhs.compare(rhs) <= 0;
}
friend bool operator>(ObjCSelector lhs, ObjCSelector rhs) {
return lhs.compare(rhs) > 0;
}
friend bool operator>=(ObjCSelector lhs, ObjCSelector rhs) {
return lhs.compare(rhs) >= 0;
}
};
} // end namespace swift
namespace llvm {
// A DeclName is "pointer like".
template<typename T> struct PointerLikeTypeTraits;
template<>
struct PointerLikeTypeTraits<swift::DeclName> {
public:
static inline void *getAsVoidPointer(swift::DeclName name) {
return name.getOpaqueValue();
}
static inline swift::DeclName getFromVoidPointer(void *ptr) {
return swift::DeclName::getFromOpaqueValue(ptr);
}
enum { NumLowBitsAvailable = PointerLikeTypeTraits<swift::DeclBaseName>::NumLowBitsAvailable - 1 };
};
// DeclNames hash just like pointers.
template<> struct DenseMapInfo<swift::DeclName> {
static swift::DeclName getEmptyKey() {
return swift::Identifier::getEmptyKey();
}
static swift::DeclName getTombstoneKey() {
return swift::Identifier::getTombstoneKey();
}
static unsigned getHashValue(swift::DeclName Val) {
return DenseMapInfo<void*>::getHashValue(Val.getOpaqueValue());
}
static bool isEqual(swift::DeclName LHS, swift::DeclName RHS) {
return LHS.getOpaqueValue() == RHS.getOpaqueValue();
}
};
// A DeclNameRef is "pointer like" just like DeclNames.
template<typename T> struct PointerLikeTypeTraits;
template<>
struct PointerLikeTypeTraits<swift::DeclNameRef> {
public:
static inline void *getAsVoidPointer(swift::DeclNameRef name) {
return name.getOpaqueValue();
}
static inline swift::DeclNameRef getFromVoidPointer(void *ptr) {
return swift::DeclNameRef::getFromOpaqueValue(ptr);
}
enum { NumLowBitsAvailable = PointerLikeTypeTraits<swift::DeclName>::NumLowBitsAvailable };
};
// DeclNameRefs hash just like DeclNames.
template<> struct DenseMapInfo<swift::DeclNameRef> {
static swift::DeclNameRef getEmptyKey() {
return swift::DeclNameRef(DenseMapInfo<swift::DeclName>::getEmptyKey());
}
static swift::DeclNameRef getTombstoneKey() {
return swift::DeclNameRef(DenseMapInfo<swift::DeclName>::getTombstoneKey());
}
static unsigned getHashValue(swift::DeclNameRef Val) {
return DenseMapInfo<swift::DeclName>::getHashValue(Val.getFullName());
}
static bool isEqual(swift::DeclNameRef LHS, swift::DeclNameRef RHS) {
return DenseMapInfo<swift::DeclName>::isEqual(LHS.getFullName(),
RHS.getFullName());
}
};
// An ObjCSelector is "pointer like".
template<typename T> struct PointerLikeTypeTraits;
template<>
struct PointerLikeTypeTraits<swift::ObjCSelector> {
public:
static inline void *getAsVoidPointer(swift::ObjCSelector name) {
return name.getOpaqueValue();
}
static inline swift::ObjCSelector getFromVoidPointer(void *ptr) {
return swift::ObjCSelector::getFromOpaqueValue(ptr);
}
enum { NumLowBitsAvailable = 0 };
};
// ObjCSelectors hash just like pointers.
template<> struct DenseMapInfo<swift::ObjCSelector> {
static swift::ObjCSelector getEmptyKey() {
return swift::ObjCSelector(DenseMapInfo<swift::DeclName>::getEmptyKey());
}
static swift::ObjCSelector getTombstoneKey() {
return swift::ObjCSelector(
DenseMapInfo<swift::DeclName>::getTombstoneKey());
}
static unsigned getHashValue(swift::ObjCSelector Val) {
return DenseMapInfo<void*>::getHashValue(Val.getOpaqueValue());
}
static bool isEqual(swift::ObjCSelector LHS, swift::ObjCSelector RHS) {
return LHS.getOpaqueValue() == RHS.getOpaqueValue();
}
};
} // end namespace llvm
#endif