Path: blob/main/contrib/llvm-project/clang/lib/Basic/IdentifierTable.cpp
35232 views
//===- IdentifierTable.cpp - Hash table for identifier lookup -------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the IdentifierInfo, IdentifierVisitor, and9// IdentifierTable interfaces.10//11//===----------------------------------------------------------------------===//1213#include "clang/Basic/IdentifierTable.h"14#include "clang/Basic/CharInfo.h"15#include "clang/Basic/DiagnosticLex.h"16#include "clang/Basic/LangOptions.h"17#include "clang/Basic/OperatorKinds.h"18#include "clang/Basic/Specifiers.h"19#include "clang/Basic/TargetBuiltins.h"20#include "clang/Basic/TokenKinds.h"21#include "llvm/ADT/DenseMapInfo.h"22#include "llvm/ADT/FoldingSet.h"23#include "llvm/ADT/SmallString.h"24#include "llvm/ADT/StringMap.h"25#include "llvm/ADT/StringRef.h"26#include "llvm/Support/Allocator.h"27#include "llvm/Support/raw_ostream.h"28#include <cassert>29#include <cstdio>30#include <cstring>31#include <string>3233using namespace clang;3435// A check to make sure the ObjCOrBuiltinID has sufficient room to store the36// largest possible target/aux-target combination. If we exceed this, we likely37// need to just change the ObjCOrBuiltinIDBits value in IdentifierTable.h.38static_assert(2 * LargestBuiltinID < (2 << (InterestingIdentifierBits - 1)),39"Insufficient ObjCOrBuiltinID Bits");4041//===----------------------------------------------------------------------===//42// IdentifierTable Implementation43//===----------------------------------------------------------------------===//4445IdentifierIterator::~IdentifierIterator() = default;4647IdentifierInfoLookup::~IdentifierInfoLookup() = default;4849namespace {5051/// A simple identifier lookup iterator that represents an52/// empty sequence of identifiers.53class EmptyLookupIterator : public IdentifierIterator {54public:55StringRef Next() override { return StringRef(); }56};5758} // namespace5960IdentifierIterator *IdentifierInfoLookup::getIdentifiers() {61return new EmptyLookupIterator();62}6364IdentifierTable::IdentifierTable(IdentifierInfoLookup *ExternalLookup)65: HashTable(8192), // Start with space for 8K identifiers.66ExternalLookup(ExternalLookup) {}6768IdentifierTable::IdentifierTable(const LangOptions &LangOpts,69IdentifierInfoLookup *ExternalLookup)70: IdentifierTable(ExternalLookup) {71// Populate the identifier table with info about keywords for the current72// language.73AddKeywords(LangOpts);74}7576//===----------------------------------------------------------------------===//77// Language Keyword Implementation78//===----------------------------------------------------------------------===//7980// Constants for TokenKinds.def81namespace {8283enum TokenKey : unsigned {84KEYC99 = 0x1,85KEYCXX = 0x2,86KEYCXX11 = 0x4,87KEYGNU = 0x8,88KEYMS = 0x10,89BOOLSUPPORT = 0x20,90KEYALTIVEC = 0x40,91KEYNOCXX = 0x80,92KEYBORLAND = 0x100,93KEYOPENCLC = 0x200,94KEYC23 = 0x400,95KEYNOMS18 = 0x800,96KEYNOOPENCL = 0x1000,97WCHARSUPPORT = 0x2000,98HALFSUPPORT = 0x4000,99CHAR8SUPPORT = 0x8000,100KEYOBJC = 0x10000,101KEYZVECTOR = 0x20000,102KEYCOROUTINES = 0x40000,103KEYMODULES = 0x80000,104KEYCXX20 = 0x100000,105KEYOPENCLCXX = 0x200000,106KEYMSCOMPAT = 0x400000,107KEYSYCL = 0x800000,108KEYCUDA = 0x1000000,109KEYHLSL = 0x2000000,110KEYFIXEDPOINT = 0x4000000,111KEYMAX = KEYFIXEDPOINT, // The maximum key112KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,113KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 &114~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude.115};116117/// How a keyword is treated in the selected standard. This enum is ordered118/// intentionally so that the value that 'wins' is the most 'permissive'.119enum KeywordStatus {120KS_Unknown, // Not yet calculated. Used when figuring out the status.121KS_Disabled, // Disabled122KS_Future, // Is a keyword in future standard123KS_Extension, // Is an extension124KS_Enabled, // Enabled125};126127} // namespace128129// This works on a single TokenKey flag and checks the LangOpts to get the130// KeywordStatus based exclusively on this flag, so that it can be merged in131// getKeywordStatus. Most should be enabled/disabled, but some might imply132// 'future' versions, or extensions. Returns 'unknown' unless this is KNOWN to133// be disabled, and the calling function makes it 'disabled' if no other flag134// changes it. This is necessary for the KEYNOCXX and KEYNOOPENCL flags.135static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,136TokenKey Flag) {137// Flag is a single bit version of TokenKey (that is, not138// KEYALL/KEYALLCXX/etc), so we can check with == throughout this function.139assert((Flag & ~(Flag - 1)) == Flag && "Multiple bits set?");140141switch (Flag) {142case KEYC99:143if (LangOpts.C99)144return KS_Enabled;145return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;146case KEYC23:147if (LangOpts.C23)148return KS_Enabled;149return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;150case KEYCXX:151return LangOpts.CPlusPlus ? KS_Enabled : KS_Unknown;152case KEYCXX11:153if (LangOpts.CPlusPlus11)154return KS_Enabled;155return LangOpts.CPlusPlus ? KS_Future : KS_Unknown;156case KEYCXX20:157if (LangOpts.CPlusPlus20)158return KS_Enabled;159return LangOpts.CPlusPlus ? KS_Future : KS_Unknown;160case KEYGNU:161return LangOpts.GNUKeywords ? KS_Extension : KS_Unknown;162case KEYMS:163return LangOpts.MicrosoftExt ? KS_Extension : KS_Unknown;164case BOOLSUPPORT:165if (LangOpts.Bool) return KS_Enabled;166return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;167case KEYALTIVEC:168return LangOpts.AltiVec ? KS_Enabled : KS_Unknown;169case KEYBORLAND:170return LangOpts.Borland ? KS_Extension : KS_Unknown;171case KEYOPENCLC:172return LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus ? KS_Enabled173: KS_Unknown;174case WCHARSUPPORT:175return LangOpts.WChar ? KS_Enabled : KS_Unknown;176case HALFSUPPORT:177return LangOpts.Half ? KS_Enabled : KS_Unknown;178case CHAR8SUPPORT:179if (LangOpts.Char8) return KS_Enabled;180if (LangOpts.CPlusPlus20) return KS_Unknown;181if (LangOpts.CPlusPlus) return KS_Future;182return KS_Unknown;183case KEYOBJC:184// We treat bridge casts as objective-C keywords so we can warn on them185// in non-arc mode.186return LangOpts.ObjC ? KS_Enabled : KS_Unknown;187case KEYZVECTOR:188return LangOpts.ZVector ? KS_Enabled : KS_Unknown;189case KEYCOROUTINES:190return LangOpts.Coroutines ? KS_Enabled : KS_Unknown;191case KEYMODULES:192return KS_Unknown;193case KEYOPENCLCXX:194return LangOpts.OpenCLCPlusPlus ? KS_Enabled : KS_Unknown;195case KEYMSCOMPAT:196return LangOpts.MSVCCompat ? KS_Enabled : KS_Unknown;197case KEYSYCL:198return LangOpts.isSYCL() ? KS_Enabled : KS_Unknown;199case KEYCUDA:200return LangOpts.CUDA ? KS_Enabled : KS_Unknown;201case KEYHLSL:202return LangOpts.HLSL ? KS_Enabled : KS_Unknown;203case KEYNOCXX:204// This is enabled in all non-C++ modes, but might be enabled for other205// reasons as well.206return LangOpts.CPlusPlus ? KS_Unknown : KS_Enabled;207case KEYNOOPENCL:208// The disable behavior for this is handled in getKeywordStatus.209return KS_Unknown;210case KEYNOMS18:211// The disable behavior for this is handled in getKeywordStatus.212return KS_Unknown;213case KEYFIXEDPOINT:214return LangOpts.FixedPoint ? KS_Enabled : KS_Disabled;215default:216llvm_unreachable("Unknown KeywordStatus flag");217}218}219220/// Translates flags as specified in TokenKinds.def into keyword status221/// in the given language standard.222static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,223unsigned Flags) {224// KEYALL means always enabled, so special case this one.225if (Flags == KEYALL) return KS_Enabled;226// These are tests that need to 'always win', as they are special in that they227// disable based on certain conditions.228if (LangOpts.OpenCL && (Flags & KEYNOOPENCL)) return KS_Disabled;229if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) &&230!LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015))231return KS_Disabled;232233KeywordStatus CurStatus = KS_Unknown;234235while (Flags != 0) {236unsigned CurFlag = Flags & ~(Flags - 1);237Flags = Flags & ~CurFlag;238CurStatus = std::max(239CurStatus,240getKeywordStatusHelper(LangOpts, static_cast<TokenKey>(CurFlag)));241}242243if (CurStatus == KS_Unknown)244return KS_Disabled;245return CurStatus;246}247248/// AddKeyword - This method is used to associate a token ID with specific249/// identifiers because they are language keywords. This causes the lexer to250/// automatically map matching identifiers to specialized token codes.251static void AddKeyword(StringRef Keyword,252tok::TokenKind TokenCode, unsigned Flags,253const LangOptions &LangOpts, IdentifierTable &Table) {254KeywordStatus AddResult = getKeywordStatus(LangOpts, Flags);255256// Don't add this keyword if disabled in this language.257if (AddResult == KS_Disabled) return;258259IdentifierInfo &Info =260Table.get(Keyword, AddResult == KS_Future ? tok::identifier : TokenCode);261Info.setIsExtensionToken(AddResult == KS_Extension);262Info.setIsFutureCompatKeyword(AddResult == KS_Future);263}264265/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative266/// representations.267static void AddCXXOperatorKeyword(StringRef Keyword,268tok::TokenKind TokenCode,269IdentifierTable &Table) {270IdentifierInfo &Info = Table.get(Keyword, TokenCode);271Info.setIsCPlusPlusOperatorKeyword();272}273274/// AddObjCKeyword - Register an Objective-C \@keyword like "class" "selector"275/// or "property".276static void AddObjCKeyword(StringRef Name,277tok::ObjCKeywordKind ObjCID,278IdentifierTable &Table) {279Table.get(Name).setObjCKeywordID(ObjCID);280}281282static void AddNotableIdentifier(StringRef Name,283tok::NotableIdentifierKind BTID,284IdentifierTable &Table) {285// Don't add 'not_notable' identifier.286if (BTID != tok::not_notable) {287IdentifierInfo &Info = Table.get(Name, tok::identifier);288Info.setNotableIdentifierID(BTID);289}290}291292/// AddKeywords - Add all keywords to the symbol table.293///294void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {295// Add keywords and tokens for the current language.296#define KEYWORD(NAME, FLAGS) \297AddKeyword(StringRef(#NAME), tok::kw_ ## NAME, \298FLAGS, LangOpts, *this);299#define ALIAS(NAME, TOK, FLAGS) \300AddKeyword(StringRef(NAME), tok::kw_ ## TOK, \301FLAGS, LangOpts, *this);302#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \303if (LangOpts.CXXOperatorNames) \304AddCXXOperatorKeyword(StringRef(#NAME), tok::ALIAS, *this);305#define OBJC_AT_KEYWORD(NAME) \306if (LangOpts.ObjC) \307AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this);308#define NOTABLE_IDENTIFIER(NAME) \309AddNotableIdentifier(StringRef(#NAME), tok::NAME, *this);310311#define TESTING_KEYWORD(NAME, FLAGS)312#include "clang/Basic/TokenKinds.def"313314if (LangOpts.ParseUnknownAnytype)315AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL,316LangOpts, *this);317318if (LangOpts.DeclSpecKeyword)319AddKeyword("__declspec", tok::kw___declspec, KEYALL, LangOpts, *this);320321if (LangOpts.IEEE128)322AddKeyword("__ieee128", tok::kw___float128, KEYALL, LangOpts, *this);323324// Add the 'import' contextual keyword.325get("import").setModulesImport(true);326}327328/// Checks if the specified token kind represents a keyword in the329/// specified language.330/// \returns Status of the keyword in the language.331static KeywordStatus getTokenKwStatus(const LangOptions &LangOpts,332tok::TokenKind K) {333switch (K) {334#define KEYWORD(NAME, FLAGS) \335case tok::kw_##NAME: return getKeywordStatus(LangOpts, FLAGS);336#include "clang/Basic/TokenKinds.def"337default: return KS_Disabled;338}339}340341/// Returns true if the identifier represents a keyword in the342/// specified language.343bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) const {344switch (getTokenKwStatus(LangOpts, getTokenID())) {345case KS_Enabled:346case KS_Extension:347return true;348default:349return false;350}351}352353/// Returns true if the identifier represents a C++ keyword in the354/// specified language.355bool IdentifierInfo::isCPlusPlusKeyword(const LangOptions &LangOpts) const {356if (!LangOpts.CPlusPlus || !isKeyword(LangOpts))357return false;358// This is a C++ keyword if this identifier is not a keyword when checked359// using LangOptions without C++ support.360LangOptions LangOptsNoCPP = LangOpts;361LangOptsNoCPP.CPlusPlus = false;362LangOptsNoCPP.CPlusPlus11 = false;363LangOptsNoCPP.CPlusPlus20 = false;364return !isKeyword(LangOptsNoCPP);365}366367ReservedIdentifierStatus368IdentifierInfo::isReserved(const LangOptions &LangOpts) const {369StringRef Name = getName();370371// '_' is a reserved identifier, but its use is so common (e.g. to store372// ignored values) that we don't warn on it.373if (Name.size() <= 1)374return ReservedIdentifierStatus::NotReserved;375376// [lex.name] p3377if (Name[0] == '_') {378379// Each name that begins with an underscore followed by an uppercase letter380// or another underscore is reserved.381if (Name[1] == '_')382return ReservedIdentifierStatus::StartsWithDoubleUnderscore;383384if ('A' <= Name[1] && Name[1] <= 'Z')385return ReservedIdentifierStatus::386StartsWithUnderscoreFollowedByCapitalLetter;387388// This is a bit misleading: it actually means it's only reserved if we're389// at global scope because it starts with an underscore.390return ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope;391}392393// Each name that contains a double underscore (__) is reserved.394if (LangOpts.CPlusPlus && Name.contains("__"))395return ReservedIdentifierStatus::ContainsDoubleUnderscore;396397return ReservedIdentifierStatus::NotReserved;398}399400ReservedLiteralSuffixIdStatus401IdentifierInfo::isReservedLiteralSuffixId() const {402StringRef Name = getName();403404if (Name[0] != '_')405return ReservedLiteralSuffixIdStatus::NotStartsWithUnderscore;406407if (Name.contains("__"))408return ReservedLiteralSuffixIdStatus::ContainsDoubleUnderscore;409410return ReservedLiteralSuffixIdStatus::NotReserved;411}412413StringRef IdentifierInfo::deuglifiedName() const {414StringRef Name = getName();415if (Name.size() >= 2 && Name.front() == '_' &&416(Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')))417return Name.ltrim('_');418return Name;419}420421tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {422// We use a perfect hash function here involving the length of the keyword,423// the first and third character. For preprocessor ID's there are no424// collisions (if there were, the switch below would complain about duplicate425// case values). Note that this depends on 'if' being null terminated.426427#define HASH(LEN, FIRST, THIRD) \428(LEN << 6) + (((FIRST - 'a') - (THIRD - 'a')) & 63)429#define CASE(LEN, FIRST, THIRD, NAME) \430case HASH(LEN, FIRST, THIRD): \431return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME432433unsigned Len = getLength();434if (Len < 2) return tok::pp_not_keyword;435const char *Name = getNameStart();436switch (HASH(Len, Name[0], Name[2])) {437default: return tok::pp_not_keyword;438CASE( 2, 'i', '\0', if);439CASE( 4, 'e', 'i', elif);440CASE( 4, 'e', 's', else);441CASE( 4, 'l', 'n', line);442CASE( 4, 's', 'c', sccs);443CASE( 5, 'e', 'b', embed);444CASE( 5, 'e', 'd', endif);445CASE( 5, 'e', 'r', error);446CASE( 5, 'i', 'e', ident);447CASE( 5, 'i', 'd', ifdef);448CASE( 5, 'u', 'd', undef);449450CASE( 6, 'a', 's', assert);451CASE( 6, 'd', 'f', define);452CASE( 6, 'i', 'n', ifndef);453CASE( 6, 'i', 'p', import);454CASE( 6, 'p', 'a', pragma);455456CASE( 7, 'd', 'f', defined);457CASE( 7, 'e', 'i', elifdef);458CASE( 7, 'i', 'c', include);459CASE( 7, 'w', 'r', warning);460461CASE( 8, 'e', 'i', elifndef);462CASE( 8, 'u', 'a', unassert);463CASE(12, 'i', 'c', include_next);464465CASE(14, '_', 'p', __public_macro);466467CASE(15, '_', 'p', __private_macro);468469CASE(16, '_', 'i', __include_macros);470#undef CASE471#undef HASH472}473}474475//===----------------------------------------------------------------------===//476// Stats Implementation477//===----------------------------------------------------------------------===//478479/// PrintStats - Print statistics about how well the identifier table is doing480/// at hashing identifiers.481void IdentifierTable::PrintStats() const {482unsigned NumBuckets = HashTable.getNumBuckets();483unsigned NumIdentifiers = HashTable.getNumItems();484unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers;485unsigned AverageIdentifierSize = 0;486unsigned MaxIdentifierLength = 0;487488// TODO: Figure out maximum times an identifier had to probe for -stats.489for (llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator>::const_iterator490I = HashTable.begin(), E = HashTable.end(); I != E; ++I) {491unsigned IdLen = I->getKeyLength();492AverageIdentifierSize += IdLen;493if (MaxIdentifierLength < IdLen)494MaxIdentifierLength = IdLen;495}496497fprintf(stderr, "\n*** Identifier Table Stats:\n");498fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers);499fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets);500fprintf(stderr, "Hash density (#identifiers per bucket): %f\n",501NumIdentifiers/(double)NumBuckets);502fprintf(stderr, "Ave identifier length: %f\n",503(AverageIdentifierSize/(double)NumIdentifiers));504fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength);505506// Compute statistics about the memory allocated for identifiers.507HashTable.getAllocator().PrintStats();508}509510//===----------------------------------------------------------------------===//511// SelectorTable Implementation512//===----------------------------------------------------------------------===//513514unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) {515return DenseMapInfo<void*>::getHashValue(S.getAsOpaquePtr());516}517518bool Selector::isKeywordSelector(ArrayRef<StringRef> Names) const {519assert(!Names.empty() && "must have >= 1 selector slots");520if (getNumArgs() != Names.size())521return false;522for (unsigned I = 0, E = Names.size(); I != E; ++I) {523if (getNameForSlot(I) != Names[I])524return false;525}526return true;527}528529bool Selector::isUnarySelector(StringRef Name) const {530return isUnarySelector() && getNameForSlot(0) == Name;531}532533unsigned Selector::getNumArgs() const {534unsigned IIF = getIdentifierInfoFlag();535if (IIF <= ZeroArg)536return 0;537if (IIF == OneArg)538return 1;539// We point to a MultiKeywordSelector.540MultiKeywordSelector *SI = getMultiKeywordSelector();541return SI->getNumArgs();542}543544const IdentifierInfo *545Selector::getIdentifierInfoForSlot(unsigned argIndex) const {546if (getIdentifierInfoFlag() < MultiArg) {547assert(argIndex == 0 && "illegal keyword index");548return getAsIdentifierInfo();549}550551// We point to a MultiKeywordSelector.552MultiKeywordSelector *SI = getMultiKeywordSelector();553return SI->getIdentifierInfoForSlot(argIndex);554}555556StringRef Selector::getNameForSlot(unsigned int argIndex) const {557const IdentifierInfo *II = getIdentifierInfoForSlot(argIndex);558return II ? II->getName() : StringRef();559}560561std::string MultiKeywordSelector::getName() const {562SmallString<256> Str;563llvm::raw_svector_ostream OS(Str);564for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) {565if (*I)566OS << (*I)->getName();567OS << ':';568}569570return std::string(OS.str());571}572573std::string Selector::getAsString() const {574if (isNull())575return "<null selector>";576577if (getIdentifierInfoFlag() < MultiArg) {578const IdentifierInfo *II = getAsIdentifierInfo();579580if (getNumArgs() == 0) {581assert(II && "If the number of arguments is 0 then II is guaranteed to "582"not be null.");583return std::string(II->getName());584}585586if (!II)587return ":";588589return II->getName().str() + ":";590}591592// We have a multiple keyword selector.593return getMultiKeywordSelector()->getName();594}595596void Selector::print(llvm::raw_ostream &OS) const {597OS << getAsString();598}599600LLVM_DUMP_METHOD void Selector::dump() const { print(llvm::errs()); }601602/// Interpreting the given string using the normal CamelCase603/// conventions, determine whether the given string starts with the604/// given "word", which is assumed to end in a lowercase letter.605static bool startsWithWord(StringRef name, StringRef word) {606if (name.size() < word.size()) return false;607return ((name.size() == word.size() || !isLowercase(name[word.size()])) &&608name.starts_with(word));609}610611ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {612const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);613if (!first) return OMF_None;614615StringRef name = first->getName();616if (sel.isUnarySelector()) {617if (name == "autorelease") return OMF_autorelease;618if (name == "dealloc") return OMF_dealloc;619if (name == "finalize") return OMF_finalize;620if (name == "release") return OMF_release;621if (name == "retain") return OMF_retain;622if (name == "retainCount") return OMF_retainCount;623if (name == "self") return OMF_self;624if (name == "initialize") return OMF_initialize;625}626627if (name == "performSelector" || name == "performSelectorInBackground" ||628name == "performSelectorOnMainThread")629return OMF_performSelector;630631// The other method families may begin with a prefix of underscores.632name = name.ltrim('_');633634if (name.empty()) return OMF_None;635switch (name.front()) {636case 'a':637if (startsWithWord(name, "alloc")) return OMF_alloc;638break;639case 'c':640if (startsWithWord(name, "copy")) return OMF_copy;641break;642case 'i':643if (startsWithWord(name, "init")) return OMF_init;644break;645case 'm':646if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy;647break;648case 'n':649if (startsWithWord(name, "new")) return OMF_new;650break;651default:652break;653}654655return OMF_None;656}657658ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) {659const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);660if (!first) return OIT_None;661662StringRef name = first->getName();663664if (name.empty()) return OIT_None;665switch (name.front()) {666case 'a':667if (startsWithWord(name, "array")) return OIT_Array;668break;669case 'd':670if (startsWithWord(name, "default")) return OIT_ReturnsSelf;671if (startsWithWord(name, "dictionary")) return OIT_Dictionary;672break;673case 's':674if (startsWithWord(name, "shared")) return OIT_ReturnsSelf;675if (startsWithWord(name, "standard")) return OIT_Singleton;676break;677case 'i':678if (startsWithWord(name, "init")) return OIT_Init;679break;680default:681break;682}683return OIT_None;684}685686ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) {687const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);688if (!first) return SFF_None;689690StringRef name = first->getName();691692switch (name.front()) {693case 'a':694if (name == "appendFormat") return SFF_NSString;695break;696697case 'i':698if (name == "initWithFormat") return SFF_NSString;699break;700701case 'l':702if (name == "localizedStringWithFormat") return SFF_NSString;703break;704705case 's':706if (name == "stringByAppendingFormat" ||707name == "stringWithFormat") return SFF_NSString;708break;709}710return SFF_None;711}712713namespace {714715struct SelectorTableImpl {716llvm::FoldingSet<MultiKeywordSelector> Table;717llvm::BumpPtrAllocator Allocator;718};719720} // namespace721722static SelectorTableImpl &getSelectorTableImpl(void *P) {723return *static_cast<SelectorTableImpl*>(P);724}725726SmallString<64>727SelectorTable::constructSetterName(StringRef Name) {728SmallString<64> SetterName("set");729SetterName += Name;730SetterName[3] = toUppercase(SetterName[3]);731return SetterName;732}733734Selector735SelectorTable::constructSetterSelector(IdentifierTable &Idents,736SelectorTable &SelTable,737const IdentifierInfo *Name) {738IdentifierInfo *SetterName =739&Idents.get(constructSetterName(Name->getName()));740return SelTable.getUnarySelector(SetterName);741}742743std::string SelectorTable::getPropertyNameFromSetterSelector(Selector Sel) {744StringRef Name = Sel.getNameForSlot(0);745assert(Name.starts_with("set") && "invalid setter name");746return (Twine(toLowercase(Name[3])) + Name.drop_front(4)).str();747}748749size_t SelectorTable::getTotalMemory() const {750SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);751return SelTabImpl.Allocator.getTotalMemory();752}753754Selector SelectorTable::getSelector(unsigned nKeys,755const IdentifierInfo **IIV) {756if (nKeys < 2)757return Selector(IIV[0], nKeys);758759SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);760761// Unique selector, to guarantee there is one per name.762llvm::FoldingSetNodeID ID;763MultiKeywordSelector::Profile(ID, IIV, nKeys);764765void *InsertPos = nullptr;766if (MultiKeywordSelector *SI =767SelTabImpl.Table.FindNodeOrInsertPos(ID, InsertPos))768return Selector(SI);769770// MultiKeywordSelector objects are not allocated with new because they have a771// variable size array (for parameter types) at the end of them.772unsigned Size = sizeof(MultiKeywordSelector) + nKeys*sizeof(IdentifierInfo *);773MultiKeywordSelector *SI =774(MultiKeywordSelector *)SelTabImpl.Allocator.Allocate(775Size, alignof(MultiKeywordSelector));776new (SI) MultiKeywordSelector(nKeys, IIV);777SelTabImpl.Table.InsertNode(SI, InsertPos);778return Selector(SI);779}780781SelectorTable::SelectorTable() {782Impl = new SelectorTableImpl();783}784785SelectorTable::~SelectorTable() {786delete &getSelectorTableImpl(Impl);787}788789const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) {790switch (Operator) {791case OO_None:792case NUM_OVERLOADED_OPERATORS:793return nullptr;794795#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \796case OO_##Name: return Spelling;797#include "clang/Basic/OperatorKinds.def"798}799800llvm_unreachable("Invalid OverloadedOperatorKind!");801}802803StringRef clang::getNullabilitySpelling(NullabilityKind kind,804bool isContextSensitive) {805switch (kind) {806case NullabilityKind::NonNull:807return isContextSensitive ? "nonnull" : "_Nonnull";808809case NullabilityKind::Nullable:810return isContextSensitive ? "nullable" : "_Nullable";811812case NullabilityKind::NullableResult:813assert(!isContextSensitive &&814"_Nullable_result isn't supported as context-sensitive keyword");815return "_Nullable_result";816817case NullabilityKind::Unspecified:818return isContextSensitive ? "null_unspecified" : "_Null_unspecified";819}820llvm_unreachable("Unknown nullability kind.");821}822823llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,824NullabilityKind NK) {825switch (NK) {826case NullabilityKind::NonNull:827return OS << "NonNull";828case NullabilityKind::Nullable:829return OS << "Nullable";830case NullabilityKind::NullableResult:831return OS << "NullableResult";832case NullabilityKind::Unspecified:833return OS << "Unspecified";834}835llvm_unreachable("Unknown nullability kind.");836}837838diag::kind839IdentifierTable::getFutureCompatDiagKind(const IdentifierInfo &II,840const LangOptions &LangOpts) {841assert(II.isFutureCompatKeyword() && "diagnostic should not be needed");842843unsigned Flags = llvm::StringSwitch<unsigned>(II.getName())844#define KEYWORD(NAME, FLAGS) .Case(#NAME, FLAGS)845#include "clang/Basic/TokenKinds.def"846#undef KEYWORD847;848849if (LangOpts.CPlusPlus) {850if ((Flags & KEYCXX11) == KEYCXX11)851return diag::warn_cxx11_keyword;852853// char8_t is not modeled as a CXX20_KEYWORD because it's not854// unconditionally enabled in C++20 mode. (It can be disabled855// by -fno-char8_t.)856if (((Flags & KEYCXX20) == KEYCXX20) ||857((Flags & CHAR8SUPPORT) == CHAR8SUPPORT))858return diag::warn_cxx20_keyword;859} else {860if ((Flags & KEYC99) == KEYC99)861return diag::warn_c99_keyword;862if ((Flags & KEYC23) == KEYC23)863return diag::warn_c23_keyword;864}865866llvm_unreachable(867"Keyword not known to come from a newer Standard or proposed Standard");868}869870871