17330f729Sjoerg //===- IdentifierTable.cpp - Hash table for identifier lookup -------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file implements the IdentifierInfo, IdentifierVisitor, and
107330f729Sjoerg // IdentifierTable interfaces.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg
147330f729Sjoerg #include "clang/Basic/IdentifierTable.h"
157330f729Sjoerg #include "clang/Basic/CharInfo.h"
167330f729Sjoerg #include "clang/Basic/LangOptions.h"
177330f729Sjoerg #include "clang/Basic/OperatorKinds.h"
187330f729Sjoerg #include "clang/Basic/Specifiers.h"
19*e038c9c4Sjoerg #include "clang/Basic/TargetBuiltins.h"
207330f729Sjoerg #include "clang/Basic/TokenKinds.h"
217330f729Sjoerg #include "llvm/ADT/DenseMapInfo.h"
227330f729Sjoerg #include "llvm/ADT/FoldingSet.h"
237330f729Sjoerg #include "llvm/ADT/SmallString.h"
247330f729Sjoerg #include "llvm/ADT/StringMap.h"
257330f729Sjoerg #include "llvm/ADT/StringRef.h"
267330f729Sjoerg #include "llvm/Support/Allocator.h"
277330f729Sjoerg #include "llvm/Support/ErrorHandling.h"
287330f729Sjoerg #include "llvm/Support/raw_ostream.h"
297330f729Sjoerg #include <cassert>
307330f729Sjoerg #include <cstdio>
317330f729Sjoerg #include <cstring>
327330f729Sjoerg #include <string>
337330f729Sjoerg
347330f729Sjoerg using namespace clang;
357330f729Sjoerg
36*e038c9c4Sjoerg // A check to make sure the ObjCOrBuiltinID has sufficient room to store the
37*e038c9c4Sjoerg // largest possible target/aux-target combination. If we exceed this, we likely
38*e038c9c4Sjoerg // need to just change the ObjCOrBuiltinIDBits value in IdentifierTable.h.
39*e038c9c4Sjoerg static_assert(2 * LargestBuiltinID < (2 << (ObjCOrBuiltinIDBits - 1)),
40*e038c9c4Sjoerg "Insufficient ObjCOrBuiltinID Bits");
41*e038c9c4Sjoerg
427330f729Sjoerg //===----------------------------------------------------------------------===//
437330f729Sjoerg // IdentifierTable Implementation
447330f729Sjoerg //===----------------------------------------------------------------------===//
457330f729Sjoerg
467330f729Sjoerg IdentifierIterator::~IdentifierIterator() = default;
477330f729Sjoerg
487330f729Sjoerg IdentifierInfoLookup::~IdentifierInfoLookup() = default;
497330f729Sjoerg
507330f729Sjoerg namespace {
517330f729Sjoerg
527330f729Sjoerg /// A simple identifier lookup iterator that represents an
537330f729Sjoerg /// empty sequence of identifiers.
547330f729Sjoerg class EmptyLookupIterator : public IdentifierIterator
557330f729Sjoerg {
567330f729Sjoerg public:
Next()577330f729Sjoerg StringRef Next() override { return StringRef(); }
587330f729Sjoerg };
597330f729Sjoerg
607330f729Sjoerg } // namespace
617330f729Sjoerg
getIdentifiers()627330f729Sjoerg IdentifierIterator *IdentifierInfoLookup::getIdentifiers() {
637330f729Sjoerg return new EmptyLookupIterator();
647330f729Sjoerg }
657330f729Sjoerg
IdentifierTable(IdentifierInfoLookup * ExternalLookup)667330f729Sjoerg IdentifierTable::IdentifierTable(IdentifierInfoLookup *ExternalLookup)
677330f729Sjoerg : HashTable(8192), // Start with space for 8K identifiers.
687330f729Sjoerg ExternalLookup(ExternalLookup) {}
697330f729Sjoerg
IdentifierTable(const LangOptions & LangOpts,IdentifierInfoLookup * ExternalLookup)707330f729Sjoerg IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
717330f729Sjoerg IdentifierInfoLookup *ExternalLookup)
727330f729Sjoerg : IdentifierTable(ExternalLookup) {
737330f729Sjoerg // Populate the identifier table with info about keywords for the current
747330f729Sjoerg // language.
757330f729Sjoerg AddKeywords(LangOpts);
767330f729Sjoerg }
777330f729Sjoerg
787330f729Sjoerg //===----------------------------------------------------------------------===//
797330f729Sjoerg // Language Keyword Implementation
807330f729Sjoerg //===----------------------------------------------------------------------===//
817330f729Sjoerg
827330f729Sjoerg // Constants for TokenKinds.def
837330f729Sjoerg namespace {
847330f729Sjoerg
857330f729Sjoerg enum {
867330f729Sjoerg KEYC99 = 0x1,
877330f729Sjoerg KEYCXX = 0x2,
887330f729Sjoerg KEYCXX11 = 0x4,
897330f729Sjoerg KEYGNU = 0x8,
907330f729Sjoerg KEYMS = 0x10,
917330f729Sjoerg BOOLSUPPORT = 0x20,
927330f729Sjoerg KEYALTIVEC = 0x40,
937330f729Sjoerg KEYNOCXX = 0x80,
947330f729Sjoerg KEYBORLAND = 0x100,
957330f729Sjoerg KEYOPENCLC = 0x200,
967330f729Sjoerg KEYC11 = 0x400,
977330f729Sjoerg KEYNOMS18 = 0x800,
987330f729Sjoerg KEYNOOPENCL = 0x1000,
997330f729Sjoerg WCHARSUPPORT = 0x2000,
1007330f729Sjoerg HALFSUPPORT = 0x4000,
1017330f729Sjoerg CHAR8SUPPORT = 0x8000,
1027330f729Sjoerg KEYCONCEPTS = 0x10000,
1037330f729Sjoerg KEYOBJC = 0x20000,
1047330f729Sjoerg KEYZVECTOR = 0x40000,
1057330f729Sjoerg KEYCOROUTINES = 0x80000,
1067330f729Sjoerg KEYMODULES = 0x100000,
107*e038c9c4Sjoerg KEYCXX20 = 0x200000,
1087330f729Sjoerg KEYOPENCLCXX = 0x400000,
1097330f729Sjoerg KEYMSCOMPAT = 0x800000,
110*e038c9c4Sjoerg KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
1117330f729Sjoerg KEYALL = (0xffffff & ~KEYNOMS18 &
1127330f729Sjoerg ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude.
1137330f729Sjoerg };
1147330f729Sjoerg
1157330f729Sjoerg /// How a keyword is treated in the selected standard.
1167330f729Sjoerg enum KeywordStatus {
1177330f729Sjoerg KS_Disabled, // Disabled
1187330f729Sjoerg KS_Extension, // Is an extension
1197330f729Sjoerg KS_Enabled, // Enabled
1207330f729Sjoerg KS_Future // Is a keyword in future standard
1217330f729Sjoerg };
1227330f729Sjoerg
1237330f729Sjoerg } // namespace
1247330f729Sjoerg
1257330f729Sjoerg /// Translates flags as specified in TokenKinds.def into keyword status
1267330f729Sjoerg /// in the given language standard.
getKeywordStatus(const LangOptions & LangOpts,unsigned Flags)1277330f729Sjoerg static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
1287330f729Sjoerg unsigned Flags) {
1297330f729Sjoerg if (Flags == KEYALL) return KS_Enabled;
1307330f729Sjoerg if (LangOpts.CPlusPlus && (Flags & KEYCXX)) return KS_Enabled;
1317330f729Sjoerg if (LangOpts.CPlusPlus11 && (Flags & KEYCXX11)) return KS_Enabled;
132*e038c9c4Sjoerg if (LangOpts.CPlusPlus20 && (Flags & KEYCXX20)) return KS_Enabled;
1337330f729Sjoerg if (LangOpts.C99 && (Flags & KEYC99)) return KS_Enabled;
1347330f729Sjoerg if (LangOpts.GNUKeywords && (Flags & KEYGNU)) return KS_Extension;
1357330f729Sjoerg if (LangOpts.MicrosoftExt && (Flags & KEYMS)) return KS_Extension;
1367330f729Sjoerg if (LangOpts.MSVCCompat && (Flags & KEYMSCOMPAT)) return KS_Enabled;
1377330f729Sjoerg if (LangOpts.Borland && (Flags & KEYBORLAND)) return KS_Extension;
1387330f729Sjoerg if (LangOpts.Bool && (Flags & BOOLSUPPORT)) return KS_Enabled;
1397330f729Sjoerg if (LangOpts.Half && (Flags & HALFSUPPORT)) return KS_Enabled;
1407330f729Sjoerg if (LangOpts.WChar && (Flags & WCHARSUPPORT)) return KS_Enabled;
1417330f729Sjoerg if (LangOpts.Char8 && (Flags & CHAR8SUPPORT)) return KS_Enabled;
1427330f729Sjoerg if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) return KS_Enabled;
1437330f729Sjoerg if (LangOpts.ZVector && (Flags & KEYZVECTOR)) return KS_Enabled;
1447330f729Sjoerg if (LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus && (Flags & KEYOPENCLC))
1457330f729Sjoerg return KS_Enabled;
1467330f729Sjoerg if (LangOpts.OpenCLCPlusPlus && (Flags & KEYOPENCLCXX)) return KS_Enabled;
1477330f729Sjoerg if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) return KS_Enabled;
1487330f729Sjoerg if (LangOpts.C11 && (Flags & KEYC11)) return KS_Enabled;
1497330f729Sjoerg // We treat bridge casts as objective-C keywords so we can warn on them
1507330f729Sjoerg // in non-arc mode.
1517330f729Sjoerg if (LangOpts.ObjC && (Flags & KEYOBJC)) return KS_Enabled;
152*e038c9c4Sjoerg if (LangOpts.CPlusPlus20 && (Flags & KEYCONCEPTS)) return KS_Enabled;
1537330f729Sjoerg if (LangOpts.Coroutines && (Flags & KEYCOROUTINES)) return KS_Enabled;
1547330f729Sjoerg if (LangOpts.ModulesTS && (Flags & KEYMODULES)) return KS_Enabled;
1557330f729Sjoerg if (LangOpts.CPlusPlus && (Flags & KEYALLCXX)) return KS_Future;
156*e038c9c4Sjoerg if (LangOpts.CPlusPlus && !LangOpts.CPlusPlus20 && (Flags & CHAR8SUPPORT))
157*e038c9c4Sjoerg return KS_Future;
1587330f729Sjoerg return KS_Disabled;
1597330f729Sjoerg }
1607330f729Sjoerg
1617330f729Sjoerg /// AddKeyword - This method is used to associate a token ID with specific
1627330f729Sjoerg /// identifiers because they are language keywords. This causes the lexer to
1637330f729Sjoerg /// automatically map matching identifiers to specialized token codes.
AddKeyword(StringRef Keyword,tok::TokenKind TokenCode,unsigned Flags,const LangOptions & LangOpts,IdentifierTable & Table)1647330f729Sjoerg static void AddKeyword(StringRef Keyword,
1657330f729Sjoerg tok::TokenKind TokenCode, unsigned Flags,
1667330f729Sjoerg const LangOptions &LangOpts, IdentifierTable &Table) {
1677330f729Sjoerg KeywordStatus AddResult = getKeywordStatus(LangOpts, Flags);
1687330f729Sjoerg
1697330f729Sjoerg // Don't add this keyword under MSVCCompat.
1707330f729Sjoerg if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) &&
1717330f729Sjoerg !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015))
1727330f729Sjoerg return;
1737330f729Sjoerg
1747330f729Sjoerg // Don't add this keyword under OpenCL.
1757330f729Sjoerg if (LangOpts.OpenCL && (Flags & KEYNOOPENCL))
1767330f729Sjoerg return;
1777330f729Sjoerg
1787330f729Sjoerg // Don't add this keyword if disabled in this language.
1797330f729Sjoerg if (AddResult == KS_Disabled) return;
1807330f729Sjoerg
1817330f729Sjoerg IdentifierInfo &Info =
1827330f729Sjoerg Table.get(Keyword, AddResult == KS_Future ? tok::identifier : TokenCode);
1837330f729Sjoerg Info.setIsExtensionToken(AddResult == KS_Extension);
1847330f729Sjoerg Info.setIsFutureCompatKeyword(AddResult == KS_Future);
1857330f729Sjoerg }
1867330f729Sjoerg
1877330f729Sjoerg /// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
1887330f729Sjoerg /// representations.
AddCXXOperatorKeyword(StringRef Keyword,tok::TokenKind TokenCode,IdentifierTable & Table)1897330f729Sjoerg static void AddCXXOperatorKeyword(StringRef Keyword,
1907330f729Sjoerg tok::TokenKind TokenCode,
1917330f729Sjoerg IdentifierTable &Table) {
1927330f729Sjoerg IdentifierInfo &Info = Table.get(Keyword, TokenCode);
1937330f729Sjoerg Info.setIsCPlusPlusOperatorKeyword();
1947330f729Sjoerg }
1957330f729Sjoerg
1967330f729Sjoerg /// AddObjCKeyword - Register an Objective-C \@keyword like "class" "selector"
1977330f729Sjoerg /// or "property".
AddObjCKeyword(StringRef Name,tok::ObjCKeywordKind ObjCID,IdentifierTable & Table)1987330f729Sjoerg static void AddObjCKeyword(StringRef Name,
1997330f729Sjoerg tok::ObjCKeywordKind ObjCID,
2007330f729Sjoerg IdentifierTable &Table) {
2017330f729Sjoerg Table.get(Name).setObjCKeywordID(ObjCID);
2027330f729Sjoerg }
2037330f729Sjoerg
2047330f729Sjoerg /// AddKeywords - Add all keywords to the symbol table.
2057330f729Sjoerg ///
AddKeywords(const LangOptions & LangOpts)2067330f729Sjoerg void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
2077330f729Sjoerg // Add keywords and tokens for the current language.
2087330f729Sjoerg #define KEYWORD(NAME, FLAGS) \
2097330f729Sjoerg AddKeyword(StringRef(#NAME), tok::kw_ ## NAME, \
2107330f729Sjoerg FLAGS, LangOpts, *this);
2117330f729Sjoerg #define ALIAS(NAME, TOK, FLAGS) \
2127330f729Sjoerg AddKeyword(StringRef(NAME), tok::kw_ ## TOK, \
2137330f729Sjoerg FLAGS, LangOpts, *this);
2147330f729Sjoerg #define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \
2157330f729Sjoerg if (LangOpts.CXXOperatorNames) \
2167330f729Sjoerg AddCXXOperatorKeyword(StringRef(#NAME), tok::ALIAS, *this);
2177330f729Sjoerg #define OBJC_AT_KEYWORD(NAME) \
2187330f729Sjoerg if (LangOpts.ObjC) \
2197330f729Sjoerg AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this);
2207330f729Sjoerg #define TESTING_KEYWORD(NAME, FLAGS)
2217330f729Sjoerg #include "clang/Basic/TokenKinds.def"
2227330f729Sjoerg
2237330f729Sjoerg if (LangOpts.ParseUnknownAnytype)
2247330f729Sjoerg AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL,
2257330f729Sjoerg LangOpts, *this);
2267330f729Sjoerg
2277330f729Sjoerg if (LangOpts.DeclSpecKeyword)
2287330f729Sjoerg AddKeyword("__declspec", tok::kw___declspec, KEYALL, LangOpts, *this);
2297330f729Sjoerg
230*e038c9c4Sjoerg if (LangOpts.IEEE128)
231*e038c9c4Sjoerg AddKeyword("__ieee128", tok::kw___float128, KEYALL, LangOpts, *this);
232*e038c9c4Sjoerg
2337330f729Sjoerg // Add the 'import' contextual keyword.
2347330f729Sjoerg get("import").setModulesImport(true);
2357330f729Sjoerg }
2367330f729Sjoerg
2377330f729Sjoerg /// Checks if the specified token kind represents a keyword in the
2387330f729Sjoerg /// specified language.
2397330f729Sjoerg /// \returns Status of the keyword in the language.
getTokenKwStatus(const LangOptions & LangOpts,tok::TokenKind K)2407330f729Sjoerg static KeywordStatus getTokenKwStatus(const LangOptions &LangOpts,
2417330f729Sjoerg tok::TokenKind K) {
2427330f729Sjoerg switch (K) {
2437330f729Sjoerg #define KEYWORD(NAME, FLAGS) \
2447330f729Sjoerg case tok::kw_##NAME: return getKeywordStatus(LangOpts, FLAGS);
2457330f729Sjoerg #include "clang/Basic/TokenKinds.def"
2467330f729Sjoerg default: return KS_Disabled;
2477330f729Sjoerg }
2487330f729Sjoerg }
2497330f729Sjoerg
2507330f729Sjoerg /// Returns true if the identifier represents a keyword in the
2517330f729Sjoerg /// specified language.
isKeyword(const LangOptions & LangOpts) const2527330f729Sjoerg bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) const {
2537330f729Sjoerg switch (getTokenKwStatus(LangOpts, getTokenID())) {
2547330f729Sjoerg case KS_Enabled:
2557330f729Sjoerg case KS_Extension:
2567330f729Sjoerg return true;
2577330f729Sjoerg default:
2587330f729Sjoerg return false;
2597330f729Sjoerg }
2607330f729Sjoerg }
2617330f729Sjoerg
2627330f729Sjoerg /// Returns true if the identifier represents a C++ keyword in the
2637330f729Sjoerg /// specified language.
isCPlusPlusKeyword(const LangOptions & LangOpts) const2647330f729Sjoerg bool IdentifierInfo::isCPlusPlusKeyword(const LangOptions &LangOpts) const {
2657330f729Sjoerg if (!LangOpts.CPlusPlus || !isKeyword(LangOpts))
2667330f729Sjoerg return false;
2677330f729Sjoerg // This is a C++ keyword if this identifier is not a keyword when checked
2687330f729Sjoerg // using LangOptions without C++ support.
2697330f729Sjoerg LangOptions LangOptsNoCPP = LangOpts;
2707330f729Sjoerg LangOptsNoCPP.CPlusPlus = false;
2717330f729Sjoerg LangOptsNoCPP.CPlusPlus11 = false;
272*e038c9c4Sjoerg LangOptsNoCPP.CPlusPlus20 = false;
2737330f729Sjoerg return !isKeyword(LangOptsNoCPP);
2747330f729Sjoerg }
2757330f729Sjoerg
276*e038c9c4Sjoerg ReservedIdentifierStatus
isReserved(const LangOptions & LangOpts) const277*e038c9c4Sjoerg IdentifierInfo::isReserved(const LangOptions &LangOpts) const {
278*e038c9c4Sjoerg StringRef Name = getName();
279*e038c9c4Sjoerg
280*e038c9c4Sjoerg // '_' is a reserved identifier, but its use is so common (e.g. to store
281*e038c9c4Sjoerg // ignored values) that we don't warn on it.
282*e038c9c4Sjoerg if (Name.size() <= 1)
283*e038c9c4Sjoerg return ReservedIdentifierStatus::NotReserved;
284*e038c9c4Sjoerg
285*e038c9c4Sjoerg // [lex.name] p3
286*e038c9c4Sjoerg if (Name[0] == '_') {
287*e038c9c4Sjoerg
288*e038c9c4Sjoerg // Each name that begins with an underscore followed by an uppercase letter
289*e038c9c4Sjoerg // or another underscore is reserved.
290*e038c9c4Sjoerg if (Name[1] == '_')
291*e038c9c4Sjoerg return ReservedIdentifierStatus::StartsWithDoubleUnderscore;
292*e038c9c4Sjoerg
293*e038c9c4Sjoerg if ('A' <= Name[1] && Name[1] <= 'Z')
294*e038c9c4Sjoerg return ReservedIdentifierStatus::
295*e038c9c4Sjoerg StartsWithUnderscoreFollowedByCapitalLetter;
296*e038c9c4Sjoerg
297*e038c9c4Sjoerg // This is a bit misleading: it actually means it's only reserved if we're
298*e038c9c4Sjoerg // at global scope because it starts with an underscore.
299*e038c9c4Sjoerg return ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope;
300*e038c9c4Sjoerg }
301*e038c9c4Sjoerg
302*e038c9c4Sjoerg // Each name that contains a double underscore (__) is reserved.
303*e038c9c4Sjoerg if (LangOpts.CPlusPlus && Name.contains("__"))
304*e038c9c4Sjoerg return ReservedIdentifierStatus::ContainsDoubleUnderscore;
305*e038c9c4Sjoerg
306*e038c9c4Sjoerg return ReservedIdentifierStatus::NotReserved;
307*e038c9c4Sjoerg }
308*e038c9c4Sjoerg
getPPKeywordID() const3097330f729Sjoerg tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
3107330f729Sjoerg // We use a perfect hash function here involving the length of the keyword,
3117330f729Sjoerg // the first and third character. For preprocessor ID's there are no
3127330f729Sjoerg // collisions (if there were, the switch below would complain about duplicate
3137330f729Sjoerg // case values). Note that this depends on 'if' being null terminated.
3147330f729Sjoerg
3157330f729Sjoerg #define HASH(LEN, FIRST, THIRD) \
3167330f729Sjoerg (LEN << 5) + (((FIRST-'a') + (THIRD-'a')) & 31)
3177330f729Sjoerg #define CASE(LEN, FIRST, THIRD, NAME) \
3187330f729Sjoerg case HASH(LEN, FIRST, THIRD): \
3197330f729Sjoerg return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME
3207330f729Sjoerg
3217330f729Sjoerg unsigned Len = getLength();
3227330f729Sjoerg if (Len < 2) return tok::pp_not_keyword;
3237330f729Sjoerg const char *Name = getNameStart();
3247330f729Sjoerg switch (HASH(Len, Name[0], Name[2])) {
3257330f729Sjoerg default: return tok::pp_not_keyword;
3267330f729Sjoerg CASE( 2, 'i', '\0', if);
3277330f729Sjoerg CASE( 4, 'e', 'i', elif);
3287330f729Sjoerg CASE( 4, 'e', 's', else);
3297330f729Sjoerg CASE( 4, 'l', 'n', line);
3307330f729Sjoerg CASE( 4, 's', 'c', sccs);
3317330f729Sjoerg CASE( 5, 'e', 'd', endif);
3327330f729Sjoerg CASE( 5, 'e', 'r', error);
3337330f729Sjoerg CASE( 5, 'i', 'e', ident);
3347330f729Sjoerg CASE( 5, 'i', 'd', ifdef);
3357330f729Sjoerg CASE( 5, 'u', 'd', undef);
3367330f729Sjoerg
3377330f729Sjoerg CASE( 6, 'a', 's', assert);
3387330f729Sjoerg CASE( 6, 'd', 'f', define);
3397330f729Sjoerg CASE( 6, 'i', 'n', ifndef);
3407330f729Sjoerg CASE( 6, 'i', 'p', import);
3417330f729Sjoerg CASE( 6, 'p', 'a', pragma);
3427330f729Sjoerg
3437330f729Sjoerg CASE( 7, 'd', 'f', defined);
3447330f729Sjoerg CASE( 7, 'i', 'c', include);
3457330f729Sjoerg CASE( 7, 'w', 'r', warning);
3467330f729Sjoerg
3477330f729Sjoerg CASE( 8, 'u', 'a', unassert);
3487330f729Sjoerg CASE(12, 'i', 'c', include_next);
3497330f729Sjoerg
3507330f729Sjoerg CASE(14, '_', 'p', __public_macro);
3517330f729Sjoerg
3527330f729Sjoerg CASE(15, '_', 'p', __private_macro);
3537330f729Sjoerg
3547330f729Sjoerg CASE(16, '_', 'i', __include_macros);
3557330f729Sjoerg #undef CASE
3567330f729Sjoerg #undef HASH
3577330f729Sjoerg }
3587330f729Sjoerg }
3597330f729Sjoerg
3607330f729Sjoerg //===----------------------------------------------------------------------===//
3617330f729Sjoerg // Stats Implementation
3627330f729Sjoerg //===----------------------------------------------------------------------===//
3637330f729Sjoerg
3647330f729Sjoerg /// PrintStats - Print statistics about how well the identifier table is doing
3657330f729Sjoerg /// at hashing identifiers.
PrintStats() const3667330f729Sjoerg void IdentifierTable::PrintStats() const {
3677330f729Sjoerg unsigned NumBuckets = HashTable.getNumBuckets();
3687330f729Sjoerg unsigned NumIdentifiers = HashTable.getNumItems();
3697330f729Sjoerg unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers;
3707330f729Sjoerg unsigned AverageIdentifierSize = 0;
3717330f729Sjoerg unsigned MaxIdentifierLength = 0;
3727330f729Sjoerg
3737330f729Sjoerg // TODO: Figure out maximum times an identifier had to probe for -stats.
3747330f729Sjoerg for (llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator>::const_iterator
3757330f729Sjoerg I = HashTable.begin(), E = HashTable.end(); I != E; ++I) {
3767330f729Sjoerg unsigned IdLen = I->getKeyLength();
3777330f729Sjoerg AverageIdentifierSize += IdLen;
3787330f729Sjoerg if (MaxIdentifierLength < IdLen)
3797330f729Sjoerg MaxIdentifierLength = IdLen;
3807330f729Sjoerg }
3817330f729Sjoerg
3827330f729Sjoerg fprintf(stderr, "\n*** Identifier Table Stats:\n");
3837330f729Sjoerg fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers);
3847330f729Sjoerg fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets);
3857330f729Sjoerg fprintf(stderr, "Hash density (#identifiers per bucket): %f\n",
3867330f729Sjoerg NumIdentifiers/(double)NumBuckets);
3877330f729Sjoerg fprintf(stderr, "Ave identifier length: %f\n",
3887330f729Sjoerg (AverageIdentifierSize/(double)NumIdentifiers));
3897330f729Sjoerg fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength);
3907330f729Sjoerg
3917330f729Sjoerg // Compute statistics about the memory allocated for identifiers.
3927330f729Sjoerg HashTable.getAllocator().PrintStats();
3937330f729Sjoerg }
3947330f729Sjoerg
3957330f729Sjoerg //===----------------------------------------------------------------------===//
3967330f729Sjoerg // SelectorTable Implementation
3977330f729Sjoerg //===----------------------------------------------------------------------===//
3987330f729Sjoerg
getHashValue(clang::Selector S)3997330f729Sjoerg unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) {
4007330f729Sjoerg return DenseMapInfo<void*>::getHashValue(S.getAsOpaquePtr());
4017330f729Sjoerg }
4027330f729Sjoerg
4037330f729Sjoerg namespace clang {
4047330f729Sjoerg
4057330f729Sjoerg /// One of these variable length records is kept for each
4067330f729Sjoerg /// selector containing more than one keyword. We use a folding set
4077330f729Sjoerg /// to unique aggregate names (keyword selectors in ObjC parlance). Access to
4087330f729Sjoerg /// this class is provided strictly through Selector.
4097330f729Sjoerg class alignas(IdentifierInfoAlignment) MultiKeywordSelector
4107330f729Sjoerg : public detail::DeclarationNameExtra,
4117330f729Sjoerg public llvm::FoldingSetNode {
MultiKeywordSelector(unsigned nKeys)4127330f729Sjoerg MultiKeywordSelector(unsigned nKeys) : DeclarationNameExtra(nKeys) {}
4137330f729Sjoerg
4147330f729Sjoerg public:
4157330f729Sjoerg // Constructor for keyword selectors.
MultiKeywordSelector(unsigned nKeys,IdentifierInfo ** IIV)4167330f729Sjoerg MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV)
4177330f729Sjoerg : DeclarationNameExtra(nKeys) {
4187330f729Sjoerg assert((nKeys > 1) && "not a multi-keyword selector");
4197330f729Sjoerg
4207330f729Sjoerg // Fill in the trailing keyword array.
4217330f729Sjoerg IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(this + 1);
4227330f729Sjoerg for (unsigned i = 0; i != nKeys; ++i)
4237330f729Sjoerg KeyInfo[i] = IIV[i];
4247330f729Sjoerg }
4257330f729Sjoerg
4267330f729Sjoerg // getName - Derive the full selector name and return it.
4277330f729Sjoerg std::string getName() const;
4287330f729Sjoerg
4297330f729Sjoerg using DeclarationNameExtra::getNumArgs;
4307330f729Sjoerg
4317330f729Sjoerg using keyword_iterator = IdentifierInfo *const *;
4327330f729Sjoerg
keyword_begin() const4337330f729Sjoerg keyword_iterator keyword_begin() const {
4347330f729Sjoerg return reinterpret_cast<keyword_iterator>(this + 1);
4357330f729Sjoerg }
4367330f729Sjoerg
keyword_end() const4377330f729Sjoerg keyword_iterator keyword_end() const {
4387330f729Sjoerg return keyword_begin() + getNumArgs();
4397330f729Sjoerg }
4407330f729Sjoerg
getIdentifierInfoForSlot(unsigned i) const4417330f729Sjoerg IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const {
4427330f729Sjoerg assert(i < getNumArgs() && "getIdentifierInfoForSlot(): illegal index");
4437330f729Sjoerg return keyword_begin()[i];
4447330f729Sjoerg }
4457330f729Sjoerg
Profile(llvm::FoldingSetNodeID & ID,keyword_iterator ArgTys,unsigned NumArgs)4467330f729Sjoerg static void Profile(llvm::FoldingSetNodeID &ID, keyword_iterator ArgTys,
4477330f729Sjoerg unsigned NumArgs) {
4487330f729Sjoerg ID.AddInteger(NumArgs);
4497330f729Sjoerg for (unsigned i = 0; i != NumArgs; ++i)
4507330f729Sjoerg ID.AddPointer(ArgTys[i]);
4517330f729Sjoerg }
4527330f729Sjoerg
Profile(llvm::FoldingSetNodeID & ID)4537330f729Sjoerg void Profile(llvm::FoldingSetNodeID &ID) {
4547330f729Sjoerg Profile(ID, keyword_begin(), getNumArgs());
4557330f729Sjoerg }
4567330f729Sjoerg };
4577330f729Sjoerg
4587330f729Sjoerg } // namespace clang.
4597330f729Sjoerg
isKeywordSelector(ArrayRef<StringRef> Names) const4607330f729Sjoerg bool Selector::isKeywordSelector(ArrayRef<StringRef> Names) const {
4617330f729Sjoerg assert(!Names.empty() && "must have >= 1 selector slots");
4627330f729Sjoerg if (getNumArgs() != Names.size())
4637330f729Sjoerg return false;
4647330f729Sjoerg for (unsigned I = 0, E = Names.size(); I != E; ++I) {
4657330f729Sjoerg if (getNameForSlot(I) != Names[I])
4667330f729Sjoerg return false;
4677330f729Sjoerg }
4687330f729Sjoerg return true;
4697330f729Sjoerg }
4707330f729Sjoerg
isUnarySelector(StringRef Name) const4717330f729Sjoerg bool Selector::isUnarySelector(StringRef Name) const {
4727330f729Sjoerg return isUnarySelector() && getNameForSlot(0) == Name;
4737330f729Sjoerg }
4747330f729Sjoerg
getNumArgs() const4757330f729Sjoerg unsigned Selector::getNumArgs() const {
4767330f729Sjoerg unsigned IIF = getIdentifierInfoFlag();
4777330f729Sjoerg if (IIF <= ZeroArg)
4787330f729Sjoerg return 0;
4797330f729Sjoerg if (IIF == OneArg)
4807330f729Sjoerg return 1;
4817330f729Sjoerg // We point to a MultiKeywordSelector.
4827330f729Sjoerg MultiKeywordSelector *SI = getMultiKeywordSelector();
4837330f729Sjoerg return SI->getNumArgs();
4847330f729Sjoerg }
4857330f729Sjoerg
getIdentifierInfoForSlot(unsigned argIndex) const4867330f729Sjoerg IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const {
4877330f729Sjoerg if (getIdentifierInfoFlag() < MultiArg) {
4887330f729Sjoerg assert(argIndex == 0 && "illegal keyword index");
4897330f729Sjoerg return getAsIdentifierInfo();
4907330f729Sjoerg }
4917330f729Sjoerg
4927330f729Sjoerg // We point to a MultiKeywordSelector.
4937330f729Sjoerg MultiKeywordSelector *SI = getMultiKeywordSelector();
4947330f729Sjoerg return SI->getIdentifierInfoForSlot(argIndex);
4957330f729Sjoerg }
4967330f729Sjoerg
getNameForSlot(unsigned int argIndex) const4977330f729Sjoerg StringRef Selector::getNameForSlot(unsigned int argIndex) const {
4987330f729Sjoerg IdentifierInfo *II = getIdentifierInfoForSlot(argIndex);
4997330f729Sjoerg return II ? II->getName() : StringRef();
5007330f729Sjoerg }
5017330f729Sjoerg
getName() const5027330f729Sjoerg std::string MultiKeywordSelector::getName() const {
5037330f729Sjoerg SmallString<256> Str;
5047330f729Sjoerg llvm::raw_svector_ostream OS(Str);
5057330f729Sjoerg for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) {
5067330f729Sjoerg if (*I)
5077330f729Sjoerg OS << (*I)->getName();
5087330f729Sjoerg OS << ':';
5097330f729Sjoerg }
5107330f729Sjoerg
511*e038c9c4Sjoerg return std::string(OS.str());
5127330f729Sjoerg }
5137330f729Sjoerg
getAsString() const5147330f729Sjoerg std::string Selector::getAsString() const {
5157330f729Sjoerg if (InfoPtr == 0)
5167330f729Sjoerg return "<null selector>";
5177330f729Sjoerg
5187330f729Sjoerg if (getIdentifierInfoFlag() < MultiArg) {
5197330f729Sjoerg IdentifierInfo *II = getAsIdentifierInfo();
5207330f729Sjoerg
5217330f729Sjoerg if (getNumArgs() == 0) {
5227330f729Sjoerg assert(II && "If the number of arguments is 0 then II is guaranteed to "
5237330f729Sjoerg "not be null.");
524*e038c9c4Sjoerg return std::string(II->getName());
5257330f729Sjoerg }
5267330f729Sjoerg
5277330f729Sjoerg if (!II)
5287330f729Sjoerg return ":";
5297330f729Sjoerg
5307330f729Sjoerg return II->getName().str() + ":";
5317330f729Sjoerg }
5327330f729Sjoerg
5337330f729Sjoerg // We have a multiple keyword selector.
5347330f729Sjoerg return getMultiKeywordSelector()->getName();
5357330f729Sjoerg }
5367330f729Sjoerg
print(llvm::raw_ostream & OS) const5377330f729Sjoerg void Selector::print(llvm::raw_ostream &OS) const {
5387330f729Sjoerg OS << getAsString();
5397330f729Sjoerg }
5407330f729Sjoerg
dump() const5417330f729Sjoerg LLVM_DUMP_METHOD void Selector::dump() const { print(llvm::errs()); }
5427330f729Sjoerg
5437330f729Sjoerg /// Interpreting the given string using the normal CamelCase
5447330f729Sjoerg /// conventions, determine whether the given string starts with the
5457330f729Sjoerg /// given "word", which is assumed to end in a lowercase letter.
startsWithWord(StringRef name,StringRef word)5467330f729Sjoerg static bool startsWithWord(StringRef name, StringRef word) {
5477330f729Sjoerg if (name.size() < word.size()) return false;
5487330f729Sjoerg return ((name.size() == word.size() || !isLowercase(name[word.size()])) &&
5497330f729Sjoerg name.startswith(word));
5507330f729Sjoerg }
5517330f729Sjoerg
getMethodFamilyImpl(Selector sel)5527330f729Sjoerg ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
5537330f729Sjoerg IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
5547330f729Sjoerg if (!first) return OMF_None;
5557330f729Sjoerg
5567330f729Sjoerg StringRef name = first->getName();
5577330f729Sjoerg if (sel.isUnarySelector()) {
5587330f729Sjoerg if (name == "autorelease") return OMF_autorelease;
5597330f729Sjoerg if (name == "dealloc") return OMF_dealloc;
5607330f729Sjoerg if (name == "finalize") return OMF_finalize;
5617330f729Sjoerg if (name == "release") return OMF_release;
5627330f729Sjoerg if (name == "retain") return OMF_retain;
5637330f729Sjoerg if (name == "retainCount") return OMF_retainCount;
5647330f729Sjoerg if (name == "self") return OMF_self;
5657330f729Sjoerg if (name == "initialize") return OMF_initialize;
5667330f729Sjoerg }
5677330f729Sjoerg
5687330f729Sjoerg if (name == "performSelector" || name == "performSelectorInBackground" ||
5697330f729Sjoerg name == "performSelectorOnMainThread")
5707330f729Sjoerg return OMF_performSelector;
5717330f729Sjoerg
5727330f729Sjoerg // The other method families may begin with a prefix of underscores.
5737330f729Sjoerg while (!name.empty() && name.front() == '_')
5747330f729Sjoerg name = name.substr(1);
5757330f729Sjoerg
5767330f729Sjoerg if (name.empty()) return OMF_None;
5777330f729Sjoerg switch (name.front()) {
5787330f729Sjoerg case 'a':
5797330f729Sjoerg if (startsWithWord(name, "alloc")) return OMF_alloc;
5807330f729Sjoerg break;
5817330f729Sjoerg case 'c':
5827330f729Sjoerg if (startsWithWord(name, "copy")) return OMF_copy;
5837330f729Sjoerg break;
5847330f729Sjoerg case 'i':
5857330f729Sjoerg if (startsWithWord(name, "init")) return OMF_init;
5867330f729Sjoerg break;
5877330f729Sjoerg case 'm':
5887330f729Sjoerg if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy;
5897330f729Sjoerg break;
5907330f729Sjoerg case 'n':
5917330f729Sjoerg if (startsWithWord(name, "new")) return OMF_new;
5927330f729Sjoerg break;
5937330f729Sjoerg default:
5947330f729Sjoerg break;
5957330f729Sjoerg }
5967330f729Sjoerg
5977330f729Sjoerg return OMF_None;
5987330f729Sjoerg }
5997330f729Sjoerg
getInstTypeMethodFamily(Selector sel)6007330f729Sjoerg ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) {
6017330f729Sjoerg IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
6027330f729Sjoerg if (!first) return OIT_None;
6037330f729Sjoerg
6047330f729Sjoerg StringRef name = first->getName();
6057330f729Sjoerg
6067330f729Sjoerg if (name.empty()) return OIT_None;
6077330f729Sjoerg switch (name.front()) {
6087330f729Sjoerg case 'a':
6097330f729Sjoerg if (startsWithWord(name, "array")) return OIT_Array;
6107330f729Sjoerg break;
6117330f729Sjoerg case 'd':
6127330f729Sjoerg if (startsWithWord(name, "default")) return OIT_ReturnsSelf;
6137330f729Sjoerg if (startsWithWord(name, "dictionary")) return OIT_Dictionary;
6147330f729Sjoerg break;
6157330f729Sjoerg case 's':
6167330f729Sjoerg if (startsWithWord(name, "shared")) return OIT_ReturnsSelf;
6177330f729Sjoerg if (startsWithWord(name, "standard")) return OIT_Singleton;
6187330f729Sjoerg break;
6197330f729Sjoerg case 'i':
6207330f729Sjoerg if (startsWithWord(name, "init")) return OIT_Init;
6217330f729Sjoerg break;
6227330f729Sjoerg default:
6237330f729Sjoerg break;
6247330f729Sjoerg }
6257330f729Sjoerg return OIT_None;
6267330f729Sjoerg }
6277330f729Sjoerg
getStringFormatFamilyImpl(Selector sel)6287330f729Sjoerg ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) {
6297330f729Sjoerg IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
6307330f729Sjoerg if (!first) return SFF_None;
6317330f729Sjoerg
6327330f729Sjoerg StringRef name = first->getName();
6337330f729Sjoerg
6347330f729Sjoerg switch (name.front()) {
6357330f729Sjoerg case 'a':
6367330f729Sjoerg if (name == "appendFormat") return SFF_NSString;
6377330f729Sjoerg break;
6387330f729Sjoerg
6397330f729Sjoerg case 'i':
6407330f729Sjoerg if (name == "initWithFormat") return SFF_NSString;
6417330f729Sjoerg break;
6427330f729Sjoerg
6437330f729Sjoerg case 'l':
6447330f729Sjoerg if (name == "localizedStringWithFormat") return SFF_NSString;
6457330f729Sjoerg break;
6467330f729Sjoerg
6477330f729Sjoerg case 's':
6487330f729Sjoerg if (name == "stringByAppendingFormat" ||
6497330f729Sjoerg name == "stringWithFormat") return SFF_NSString;
6507330f729Sjoerg break;
6517330f729Sjoerg }
6527330f729Sjoerg return SFF_None;
6537330f729Sjoerg }
6547330f729Sjoerg
6557330f729Sjoerg namespace {
6567330f729Sjoerg
6577330f729Sjoerg struct SelectorTableImpl {
6587330f729Sjoerg llvm::FoldingSet<MultiKeywordSelector> Table;
6597330f729Sjoerg llvm::BumpPtrAllocator Allocator;
6607330f729Sjoerg };
6617330f729Sjoerg
6627330f729Sjoerg } // namespace
6637330f729Sjoerg
getSelectorTableImpl(void * P)6647330f729Sjoerg static SelectorTableImpl &getSelectorTableImpl(void *P) {
6657330f729Sjoerg return *static_cast<SelectorTableImpl*>(P);
6667330f729Sjoerg }
6677330f729Sjoerg
6687330f729Sjoerg SmallString<64>
constructSetterName(StringRef Name)6697330f729Sjoerg SelectorTable::constructSetterName(StringRef Name) {
6707330f729Sjoerg SmallString<64> SetterName("set");
6717330f729Sjoerg SetterName += Name;
6727330f729Sjoerg SetterName[3] = toUppercase(SetterName[3]);
6737330f729Sjoerg return SetterName;
6747330f729Sjoerg }
6757330f729Sjoerg
6767330f729Sjoerg Selector
constructSetterSelector(IdentifierTable & Idents,SelectorTable & SelTable,const IdentifierInfo * Name)6777330f729Sjoerg SelectorTable::constructSetterSelector(IdentifierTable &Idents,
6787330f729Sjoerg SelectorTable &SelTable,
6797330f729Sjoerg const IdentifierInfo *Name) {
6807330f729Sjoerg IdentifierInfo *SetterName =
6817330f729Sjoerg &Idents.get(constructSetterName(Name->getName()));
6827330f729Sjoerg return SelTable.getUnarySelector(SetterName);
6837330f729Sjoerg }
6847330f729Sjoerg
getPropertyNameFromSetterSelector(Selector Sel)6857330f729Sjoerg std::string SelectorTable::getPropertyNameFromSetterSelector(Selector Sel) {
6867330f729Sjoerg StringRef Name = Sel.getNameForSlot(0);
6877330f729Sjoerg assert(Name.startswith("set") && "invalid setter name");
6887330f729Sjoerg return (Twine(toLowercase(Name[3])) + Name.drop_front(4)).str();
6897330f729Sjoerg }
6907330f729Sjoerg
getTotalMemory() const6917330f729Sjoerg size_t SelectorTable::getTotalMemory() const {
6927330f729Sjoerg SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
6937330f729Sjoerg return SelTabImpl.Allocator.getTotalMemory();
6947330f729Sjoerg }
6957330f729Sjoerg
getSelector(unsigned nKeys,IdentifierInfo ** IIV)6967330f729Sjoerg Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) {
6977330f729Sjoerg if (nKeys < 2)
6987330f729Sjoerg return Selector(IIV[0], nKeys);
6997330f729Sjoerg
7007330f729Sjoerg SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
7017330f729Sjoerg
7027330f729Sjoerg // Unique selector, to guarantee there is one per name.
7037330f729Sjoerg llvm::FoldingSetNodeID ID;
7047330f729Sjoerg MultiKeywordSelector::Profile(ID, IIV, nKeys);
7057330f729Sjoerg
7067330f729Sjoerg void *InsertPos = nullptr;
7077330f729Sjoerg if (MultiKeywordSelector *SI =
7087330f729Sjoerg SelTabImpl.Table.FindNodeOrInsertPos(ID, InsertPos))
7097330f729Sjoerg return Selector(SI);
7107330f729Sjoerg
7117330f729Sjoerg // MultiKeywordSelector objects are not allocated with new because they have a
7127330f729Sjoerg // variable size array (for parameter types) at the end of them.
7137330f729Sjoerg unsigned Size = sizeof(MultiKeywordSelector) + nKeys*sizeof(IdentifierInfo *);
7147330f729Sjoerg MultiKeywordSelector *SI =
7157330f729Sjoerg (MultiKeywordSelector *)SelTabImpl.Allocator.Allocate(
7167330f729Sjoerg Size, alignof(MultiKeywordSelector));
7177330f729Sjoerg new (SI) MultiKeywordSelector(nKeys, IIV);
7187330f729Sjoerg SelTabImpl.Table.InsertNode(SI, InsertPos);
7197330f729Sjoerg return Selector(SI);
7207330f729Sjoerg }
7217330f729Sjoerg
SelectorTable()7227330f729Sjoerg SelectorTable::SelectorTable() {
7237330f729Sjoerg Impl = new SelectorTableImpl();
7247330f729Sjoerg }
7257330f729Sjoerg
~SelectorTable()7267330f729Sjoerg SelectorTable::~SelectorTable() {
7277330f729Sjoerg delete &getSelectorTableImpl(Impl);
7287330f729Sjoerg }
7297330f729Sjoerg
getOperatorSpelling(OverloadedOperatorKind Operator)7307330f729Sjoerg const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) {
7317330f729Sjoerg switch (Operator) {
7327330f729Sjoerg case OO_None:
7337330f729Sjoerg case NUM_OVERLOADED_OPERATORS:
7347330f729Sjoerg return nullptr;
7357330f729Sjoerg
7367330f729Sjoerg #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
7377330f729Sjoerg case OO_##Name: return Spelling;
7387330f729Sjoerg #include "clang/Basic/OperatorKinds.def"
7397330f729Sjoerg }
7407330f729Sjoerg
7417330f729Sjoerg llvm_unreachable("Invalid OverloadedOperatorKind!");
7427330f729Sjoerg }
7437330f729Sjoerg
getNullabilitySpelling(NullabilityKind kind,bool isContextSensitive)7447330f729Sjoerg StringRef clang::getNullabilitySpelling(NullabilityKind kind,
7457330f729Sjoerg bool isContextSensitive) {
7467330f729Sjoerg switch (kind) {
7477330f729Sjoerg case NullabilityKind::NonNull:
7487330f729Sjoerg return isContextSensitive ? "nonnull" : "_Nonnull";
7497330f729Sjoerg
7507330f729Sjoerg case NullabilityKind::Nullable:
7517330f729Sjoerg return isContextSensitive ? "nullable" : "_Nullable";
7527330f729Sjoerg
753*e038c9c4Sjoerg case NullabilityKind::NullableResult:
754*e038c9c4Sjoerg assert(!isContextSensitive &&
755*e038c9c4Sjoerg "_Nullable_result isn't supported as context-sensitive keyword");
756*e038c9c4Sjoerg return "_Nullable_result";
757*e038c9c4Sjoerg
7587330f729Sjoerg case NullabilityKind::Unspecified:
7597330f729Sjoerg return isContextSensitive ? "null_unspecified" : "_Null_unspecified";
7607330f729Sjoerg }
7617330f729Sjoerg llvm_unreachable("Unknown nullability kind.");
7627330f729Sjoerg }
763