//===--- Identifier.h - Uniqued Identifier ----------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2025 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 /// `Identifier.h` is imported into Swift. Be *very* careful with what you /// include here and keep these includes minimal! /// If you don't need to import a header into Swift, include it in the `#ifdef` /// block below instead. /// /// See include guidelines and caveats in `BasicBridging.h`. #include "swift/Basic/SwiftBridging.h" #include #include // Not imported into Swift in pure bridging mode. #ifdef NOT_COMPILED_WITH_SWIFT_PURE_BRIDGING_MODE #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" #endif // #ifdef NOT_COMPILED_WITH_SWIFT_PURE_BRIDGING_MODE SWIFT_BEGIN_NULLABILITY_ANNOTATIONS 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 *_Nullable 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 *_Nullable 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) {} SWIFT_UNAVAILABLE("Use 'init(raw:)' instead") static Identifier getFromOpaquePointer(const void *_Nullable P) { return Identifier((const char *)P); } #ifdef COMPILED_WITH_SWIFT SWIFT_NAME("init(raw:)") Identifier(const void *_Nullable raw) : Pointer((const char *)raw) {} #endif SWIFT_UNAVAILABLE("Use 'raw' instead") const void *_Nullable getAsOpaquePointer() const { return static_cast(Pointer); } #ifdef COMPILED_WITH_SWIFT SWIFT_COMPUTED_PROPERTY SWIFT_IMPORT_UNSAFE const void *_Nullable getRaw() const { return getAsOpaquePointer(); } #endif SWIFT_UNAVAILABLE("Use 'isValid' instead") bool empty() const { return Pointer == nullptr; } SWIFT_UNAVAILABLE("Use 'isValid' instead") bool nonempty() const { return !empty(); } #ifdef COMPILED_WITH_SWIFT SWIFT_COMPUTED_PROPERTY bool getIsValid() const { return empty(); } #endif /// isOperator - Return true if this identifier is an operator, false if it is /// a normal identifier. bool isOperator() const { if (empty()) return false; if (isEditorPlaceholder()) return false; // Handle the high unicode case out of line. return isOperatorSlow(); } SWIFT_UNAVAILABLE("Unavailable in Swift") bool isEditorPlaceholder() const; // Not imported into Swift in pure bridging mode. #ifdef NOT_COMPILED_WITH_SWIFT_PURE_BRIDGING_MODE const char *_Nullable get() const { return Pointer; } unsigned getLength() const { assert(Pointer != nullptr && "Tried getting length of empty identifier"); return ::strlen(Pointer); } static bool isEditorPlaceholder(StringRef name) { return swift::isEditorPlaceholder(name); } /// Returns true if this identifier contains non-identifier characters and /// must always be escaped with backticks, even in contexts were other /// escaped identifiers could omit backticks (like keywords as argument /// labels). bool mustAlwaysBeEscaped() const; bool isArithmeticOperator() const { return is("+") || is("-") || is("*") || is("/") || is("%"); } bool isBitwiseOperator() const { return is("~") || is("&") || is("|") || is("^"); } bool isShiftOperator() const { return 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("??"); } // Returns whether this is a standard infix logical operator, // such as '&&', '||'. bool isStandardInfixLogicalOperator() const { return is("&&") || 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); } StringRef str() const { return Pointer; } bool hasDollarPrefix() const { return str().starts_with("$") && !(getLength() == 1); } bool hasUnderscoredNaming() const { return str().starts_with("_"); } LLVM_ATTRIBUTE_USED bool is(StringRef string) const { return str() == string; } /// 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; explicit operator std::string() const { return std::string(Pointer); } 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(-1); Val <<= NumLowBitsAvailable; return Identifier((const char*)Val); } static Identifier getTombstoneKey() { uintptr_t Val = static_cast(-2); Val <<= NumLowBitsAvailable; return Identifier((const char*)Val); } #endif // #ifdef NOT_COMPILED_WITH_SWIFT_PURE_BRIDGING_MODE private: bool isOperatorSlow() const; }; class DeclName; class DeclNameRef; class ObjCSelector; } // end namespace swift // Not imported into Swift in pure bridging mode. #ifdef NOT_COMPILED_WITH_SWIFT_PURE_BRIDGING_MODE 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 { static swift::Identifier getEmptyKey() { return swift::Identifier::getEmptyKey(); } static swift::Identifier getTombstoneKey() { return swift::Identifier::getTombstoneKey(); } static unsigned getHashValue(swift::Identifier Val) { return DenseMapInfo::getHashValue(Val.get()); } static bool isEqual(swift::Identifier LHS, swift::Identifier RHS) { return LHS == RHS; } }; // An Identifier is "pointer like". template struct PointerLikeTypeTraits; template<> struct PointerLikeTypeTraits { public: static inline void *_Nullable getAsVoidPointer(swift::Identifier I) { return const_cast(I.getAsOpaquePointer()); } static inline swift::Identifier getFromVoidPointer(void *_Nullable P) { return swift::Identifier::getFromOpaquePointer(P); } enum { NumLowBitsAvailable = swift::Identifier::NumLowBitsAvailable }; }; } // end namespace llvm #endif // #ifdef NOT_COMPILED_WITH_SWIFT_PURE_BRIDGING_MODE 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)); } // Not imported into Swift in pure bridging mode. #ifdef NOT_COMPILED_WITH_SWIFT_PURE_BRIDGING_MODE 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; } bool isConstructor() const { return getKind() == Kind::Constructor; } /// 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 mustAlwaysBeEscaped() const { return !isSpecial() && getIdentifier().mustAlwaysBeEscaped(); } bool isEditorPlaceholder() const { return !isSpecial() && getIdentifier().isEditorPlaceholder(); } bool hasDollarPrefix() const { return !isSpecial() && 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 { if (int result = userFacingName().compare(other.userFacingName())) return result; if (getKind() == other.getKind()) return 0; return getKind() < other.getKind() ? -1 : 1; } 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 *_Nullable getAsOpaquePointer() const { return Ident.get(); } static DeclBaseName getFromOpaquePointer(void *_Nullable P) { return Identifier::getFromOpaquePointer(P); } #endif // #ifdef NOT_COMPILED_WITH_SWIFT_PURE_BRIDGING_MODE }; } // end namespace swift // Not imported into Swift in pure bridging mode. #ifdef NOT_COMPILED_WITH_SWIFT_PURE_BRIDGING_MODE namespace llvm { raw_ostream &operator<<(raw_ostream &OS, swift::DeclBaseName D); // DeclBaseNames hash just like pointers. template<> struct DenseMapInfo { static swift::DeclBaseName getEmptyKey() { return swift::Identifier::getEmptyKey(); } static swift::DeclBaseName getTombstoneKey() { return swift::Identifier::getTombstoneKey(); } static unsigned getHashValue(swift::DeclBaseName Val) { return DenseMapInfo::getHashValue(Val.getAsOpaquePointer()); } static bool isEqual(swift::DeclBaseName LHS, swift::DeclBaseName RHS) { return LHS == RHS; } }; // A DeclBaseName is "pointer like". template struct PointerLikeTypeTraits; template <> struct PointerLikeTypeTraits { public: static inline void *_Nullable getAsVoidPointer(swift::DeclBaseName D) { return const_cast(D.getAsOpaquePointer()); } static inline swift::DeclBaseName getFromVoidPointer(void *_Nullable P) { return swift::DeclBaseName::getFromOpaquePointer(P); } enum { NumLowBitsAvailable = PointerLikeTypeTraits::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 { friend TrailingObjects; friend class DeclName; DeclBaseName BaseName; size_t NumArgs; explicit CompoundDeclName(DeclBaseName BaseName, size_t NumArgs) : BaseName(BaseName), NumArgs(NumArgs) { } ArrayRef getArgumentNames() const { return {getTrailingObjects(), NumArgs}; } MutableArrayRef getArgumentNames() { return {getTrailingObjects(), NumArgs}; } /// Uniquing for the ASTContext. static void Profile(llvm::FoldingSetNodeID &id, DeclBaseName baseName, ArrayRef 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 BaseNameOrCompound; explicit DeclName(void *_Nullable Opaque) : BaseNameOrCompound( decltype(BaseNameOrCompound)::getFromOpaqueValue(Opaque)) {} void initialize(ASTContext &C, DeclBaseName baseName, ArrayRef 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 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 *_Nonnull 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()) return compound->BaseName; return cast(BaseNameOrCompound); } /// 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 getArgumentNames() const { if (auto compound = BaseNameOrCompound.dyn_cast()) return compound->getArgumentNames(); return { }; } bool isSpecial() const { return getBaseName().isSpecial(); } explicit operator bool() const { if (BaseNameOrCompound.dyn_cast()) return true; return !cast(BaseNameOrCompound).empty(); } /// True if this is a simple one-component name. bool isSimpleName() const { return isa(BaseNameOrCompound); } /// 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 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 args) const; /// True if this name is an operator. bool isOperator() const { return getBaseName().isOperator(); } /// True if this name is an escaped identifier. bool mustAlwaysBeEscaped() const { return getBaseName().mustAlwaysBeEscaped(); } /// 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 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 *_Nullable getOpaqueValue() const { return BaseNameOrCompound.getOpaqueValue(); } static DeclName getFromOpaqueValue(void *_Nullable p) { return DeclName(p); } /// Get a string representation of the name, /// /// \param scratch Scratch space to use. StringRef getString(llvm::SmallVectorImpl &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. /// /// \param escapeIfNeeded When true, escape identifiers with backticks /// when required. llvm::raw_ostream &print(llvm::raw_ostream &os, bool skipEmptyArgumentNames = false, bool escapeIfNeeded = 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 *_Nullable getOpaqueValue() const { return FullName.getOpaqueValue(); } static DeclNameRef getFromOpaqueValue(void *_Nullable p); explicit DeclNameRef(ASTContext &C, Identifier moduleSelector, DeclName fullName) : FullName(fullName) { } explicit DeclNameRef(ASTContext &C, Identifier moduleSelector, DeclBaseName baseName, ArrayRef argLabels) : FullName(C, baseName, argLabels) { } explicit DeclNameRef(DeclName FullName) : FullName(FullName) { } bool hasModuleSelector() const { return false; } Identifier getModuleSelector() const { return Identifier(); } /// The name of the declaration being referenced. DeclName getFullName() const { return FullName; } /// The base name of the declaration being referenced. DeclBaseName getBaseName() const { return getFullName().getBaseName(); } Identifier getBaseIdentifier() const { return getFullName().getBaseIdentifier(); } ArrayRef getArgumentNames() const { return getFullName().getArgumentNames(); } bool isSimpleName() const { return getFullName().isSimpleName(); } bool isSimpleName(DeclBaseName name) const { return getFullName().isSimpleName(name); } bool isSimpleName(StringRef name) const { return getFullName().isSimpleName(name); } bool isSpecial() const { return getFullName().isSpecial(); } bool isOperator() const { return getFullName().isOperator(); } bool mustAlwaysBeEscaped() const { return getFullName().mustAlwaysBeEscaped(); } bool isCompoundName() const { return getFullName().isCompoundName(); } explicit operator bool() const { return (bool)getFullName(); } /// 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(ASTContext &C) const; DeclNameRef withArgumentLabels(ASTContext &C, ArrayRef argumentNames) const; /// Get a string representation of the name, /// /// \param scratch Scratch space to use. StringRef getString(llvm::SmallVectorImpl &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 *_Nullable p) { return DeclNameRef(DeclName::getFromOpaqueValue(p)); } inline DeclNameRef DeclNameRef::withoutArgumentLabels(ASTContext &C) const { return DeclNameRef(C, getModuleSelector(), getBaseName()); } inline DeclNameRef DeclNameRef::withArgumentLabels( ASTContext &C, ArrayRef argumentNames) const { return DeclNameRef(C, getModuleSelector(), 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; public: /// Form a selector with the given number of arguments and the given selector /// pieces. ObjCSelector(ASTContext &ctx, unsigned numArgs, ArrayRef 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 std::optional 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 getSelectorPieces() const { if (Storage.isSimpleName()) { return { reinterpret_cast(&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 &scratch) const; ObjCSelectorFamily getSelectorFamily() const; void *_Nullable getOpaqueValue() const { return Storage.getOpaqueValue(); } static ObjCSelector getFromOpaqueValue(void *_Nullable 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 struct PointerLikeTypeTraits; template<> struct PointerLikeTypeTraits { public: static inline void *_Nullable getAsVoidPointer(swift::DeclName name) { return name.getOpaqueValue(); } static inline swift::DeclName getFromVoidPointer(void *_Nullable ptr) { return swift::DeclName::getFromOpaqueValue(ptr); } enum { NumLowBitsAvailable = PointerLikeTypeTraits::NumLowBitsAvailable - 1 }; }; // DeclNames hash just like pointers. template<> struct DenseMapInfo { static swift::DeclName getEmptyKey() { return swift::Identifier::getEmptyKey(); } static swift::DeclName getTombstoneKey() { return swift::Identifier::getTombstoneKey(); } static unsigned getHashValue(swift::DeclName Val) { return DenseMapInfo::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 struct PointerLikeTypeTraits; template<> struct PointerLikeTypeTraits { public: static inline void *_Nullable getAsVoidPointer(swift::DeclNameRef name) { return name.getOpaqueValue(); } static inline swift::DeclNameRef getFromVoidPointer(void *_Nullable ptr) { return swift::DeclNameRef::getFromOpaqueValue(ptr); } enum { NumLowBitsAvailable = PointerLikeTypeTraits::NumLowBitsAvailable }; }; // DeclNameRefs hash just like DeclNames. template<> struct DenseMapInfo { static swift::DeclNameRef getEmptyKey() { return swift::DeclNameRef(DenseMapInfo::getEmptyKey()); } static swift::DeclNameRef getTombstoneKey() { return swift::DeclNameRef(DenseMapInfo::getTombstoneKey()); } static unsigned getHashValue(swift::DeclNameRef Val) { return DenseMapInfo::getHashValue(Val.getFullName()); } static bool isEqual(swift::DeclNameRef LHS, swift::DeclNameRef RHS) { return DenseMapInfo::isEqual(LHS.getFullName(), RHS.getFullName()); } }; // An ObjCSelector is "pointer like". template struct PointerLikeTypeTraits; template<> struct PointerLikeTypeTraits { public: static inline void *_Nullable getAsVoidPointer(swift::ObjCSelector name) { return name.getOpaqueValue(); } static inline swift::ObjCSelector getFromVoidPointer(void *_Nullable ptr) { return swift::ObjCSelector::getFromOpaqueValue(ptr); } enum { NumLowBitsAvailable = 0 }; }; // ObjCSelectors hash just like pointers. template<> struct DenseMapInfo { static swift::ObjCSelector getEmptyKey() { return swift::ObjCSelector(DenseMapInfo::getEmptyKey()); } static swift::ObjCSelector getTombstoneKey() { return swift::ObjCSelector( DenseMapInfo::getTombstoneKey()); } static unsigned getHashValue(swift::ObjCSelector Val) { return DenseMapInfo::getHashValue(Val.getOpaqueValue()); } static bool isEqual(swift::ObjCSelector LHS, swift::ObjCSelector RHS) { return LHS.getOpaqueValue() == RHS.getOpaqueValue(); } }; } // end namespace llvm #endif // #ifdef NOT_COMPILED_WITH_SWIFT_PURE_BRIDGING_MODE SWIFT_END_NULLABILITY_ANNOTATIONS #endif // #ifndef SWIFT_AST_IDENTIFIER_H