10b57cec5SDimitry Andric //===- IdentifierTable.cpp - Hash table for identifier lookup -------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the IdentifierInfo, IdentifierVisitor, and
100b57cec5SDimitry Andric // IdentifierTable interfaces.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h"
150b57cec5SDimitry Andric #include "clang/Basic/CharInfo.h"
16bdd1243dSDimitry Andric #include "clang/Basic/DiagnosticLex.h"
170b57cec5SDimitry Andric #include "clang/Basic/LangOptions.h"
180b57cec5SDimitry Andric #include "clang/Basic/OperatorKinds.h"
190b57cec5SDimitry Andric #include "clang/Basic/Specifiers.h"
205ffd83dbSDimitry Andric #include "clang/Basic/TargetBuiltins.h"
210b57cec5SDimitry Andric #include "clang/Basic/TokenKinds.h"
220b57cec5SDimitry Andric #include "llvm/ADT/DenseMapInfo.h"
230b57cec5SDimitry Andric #include "llvm/ADT/FoldingSet.h"
240b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
250b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h"
260b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
270b57cec5SDimitry Andric #include "llvm/Support/Allocator.h"
280b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
290b57cec5SDimitry Andric #include <cassert>
300b57cec5SDimitry Andric #include <cstdio>
310b57cec5SDimitry Andric #include <cstring>
320b57cec5SDimitry Andric #include <string>
330b57cec5SDimitry Andric
340b57cec5SDimitry Andric using namespace clang;
350b57cec5SDimitry Andric
365ffd83dbSDimitry Andric // A check to make sure the ObjCOrBuiltinID has sufficient room to store the
375ffd83dbSDimitry Andric // largest possible target/aux-target combination. If we exceed this, we likely
385ffd83dbSDimitry Andric // need to just change the ObjCOrBuiltinIDBits value in IdentifierTable.h.
39*0fca6ea1SDimitry Andric static_assert(2 * LargestBuiltinID < (2 << (InterestingIdentifierBits - 1)),
405ffd83dbSDimitry Andric "Insufficient ObjCOrBuiltinID Bits");
415ffd83dbSDimitry Andric
420b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
430b57cec5SDimitry Andric // IdentifierTable Implementation
440b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
450b57cec5SDimitry Andric
460b57cec5SDimitry Andric IdentifierIterator::~IdentifierIterator() = default;
470b57cec5SDimitry Andric
480b57cec5SDimitry Andric IdentifierInfoLookup::~IdentifierInfoLookup() = default;
490b57cec5SDimitry Andric
500b57cec5SDimitry Andric namespace {
510b57cec5SDimitry Andric
520b57cec5SDimitry Andric /// A simple identifier lookup iterator that represents an
530b57cec5SDimitry Andric /// empty sequence of identifiers.
545f757f3fSDimitry Andric class EmptyLookupIterator : public IdentifierIterator {
550b57cec5SDimitry Andric public:
Next()560b57cec5SDimitry Andric StringRef Next() override { return StringRef(); }
570b57cec5SDimitry Andric };
580b57cec5SDimitry Andric
590b57cec5SDimitry Andric } // namespace
600b57cec5SDimitry Andric
getIdentifiers()610b57cec5SDimitry Andric IdentifierIterator *IdentifierInfoLookup::getIdentifiers() {
620b57cec5SDimitry Andric return new EmptyLookupIterator();
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric
IdentifierTable(IdentifierInfoLookup * ExternalLookup)650b57cec5SDimitry Andric IdentifierTable::IdentifierTable(IdentifierInfoLookup *ExternalLookup)
660b57cec5SDimitry Andric : HashTable(8192), // Start with space for 8K identifiers.
670b57cec5SDimitry Andric ExternalLookup(ExternalLookup) {}
680b57cec5SDimitry Andric
IdentifierTable(const LangOptions & LangOpts,IdentifierInfoLookup * ExternalLookup)690b57cec5SDimitry Andric IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
700b57cec5SDimitry Andric IdentifierInfoLookup *ExternalLookup)
710b57cec5SDimitry Andric : IdentifierTable(ExternalLookup) {
720b57cec5SDimitry Andric // Populate the identifier table with info about keywords for the current
730b57cec5SDimitry Andric // language.
740b57cec5SDimitry Andric AddKeywords(LangOpts);
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric
770b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
780b57cec5SDimitry Andric // Language Keyword Implementation
790b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
800b57cec5SDimitry Andric
810b57cec5SDimitry Andric // Constants for TokenKinds.def
820b57cec5SDimitry Andric namespace {
830b57cec5SDimitry Andric
84bdd1243dSDimitry Andric enum TokenKey : unsigned {
850b57cec5SDimitry Andric KEYC99 = 0x1,
860b57cec5SDimitry Andric KEYCXX = 0x2,
870b57cec5SDimitry Andric KEYCXX11 = 0x4,
880b57cec5SDimitry Andric KEYGNU = 0x8,
890b57cec5SDimitry Andric KEYMS = 0x10,
900b57cec5SDimitry Andric BOOLSUPPORT = 0x20,
910b57cec5SDimitry Andric KEYALTIVEC = 0x40,
920b57cec5SDimitry Andric KEYNOCXX = 0x80,
930b57cec5SDimitry Andric KEYBORLAND = 0x100,
940b57cec5SDimitry Andric KEYOPENCLC = 0x200,
955f757f3fSDimitry Andric KEYC23 = 0x400,
960b57cec5SDimitry Andric KEYNOMS18 = 0x800,
970b57cec5SDimitry Andric KEYNOOPENCL = 0x1000,
980b57cec5SDimitry Andric WCHARSUPPORT = 0x2000,
990b57cec5SDimitry Andric HALFSUPPORT = 0x4000,
1000b57cec5SDimitry Andric CHAR8SUPPORT = 0x8000,
101bdd1243dSDimitry Andric KEYOBJC = 0x10000,
102bdd1243dSDimitry Andric KEYZVECTOR = 0x20000,
103bdd1243dSDimitry Andric KEYCOROUTINES = 0x40000,
104bdd1243dSDimitry Andric KEYMODULES = 0x80000,
105bdd1243dSDimitry Andric KEYCXX20 = 0x100000,
106bdd1243dSDimitry Andric KEYOPENCLCXX = 0x200000,
107bdd1243dSDimitry Andric KEYMSCOMPAT = 0x400000,
108bdd1243dSDimitry Andric KEYSYCL = 0x800000,
109bdd1243dSDimitry Andric KEYCUDA = 0x1000000,
110bdd1243dSDimitry Andric KEYHLSL = 0x2000000,
1115f757f3fSDimitry Andric KEYFIXEDPOINT = 0x4000000,
1125f757f3fSDimitry Andric KEYMAX = KEYFIXEDPOINT, // The maximum key
1135ffd83dbSDimitry Andric KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
11481ad6265SDimitry Andric KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 &
11581ad6265SDimitry Andric ~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude.
1160b57cec5SDimitry Andric };
1170b57cec5SDimitry Andric
118bdd1243dSDimitry Andric /// How a keyword is treated in the selected standard. This enum is ordered
119bdd1243dSDimitry Andric /// intentionally so that the value that 'wins' is the most 'permissive'.
1200b57cec5SDimitry Andric enum KeywordStatus {
121bdd1243dSDimitry Andric KS_Unknown, // Not yet calculated. Used when figuring out the status.
1220b57cec5SDimitry Andric KS_Disabled, // Disabled
123bdd1243dSDimitry Andric KS_Future, // Is a keyword in future standard
1240b57cec5SDimitry Andric KS_Extension, // Is an extension
1250b57cec5SDimitry Andric KS_Enabled, // Enabled
1260b57cec5SDimitry Andric };
1270b57cec5SDimitry Andric
1280b57cec5SDimitry Andric } // namespace
1290b57cec5SDimitry Andric
130bdd1243dSDimitry Andric // This works on a single TokenKey flag and checks the LangOpts to get the
131bdd1243dSDimitry Andric // KeywordStatus based exclusively on this flag, so that it can be merged in
132bdd1243dSDimitry Andric // getKeywordStatus. Most should be enabled/disabled, but some might imply
133bdd1243dSDimitry Andric // 'future' versions, or extensions. Returns 'unknown' unless this is KNOWN to
134bdd1243dSDimitry Andric // be disabled, and the calling function makes it 'disabled' if no other flag
135bdd1243dSDimitry Andric // changes it. This is necessary for the KEYNOCXX and KEYNOOPENCL flags.
getKeywordStatusHelper(const LangOptions & LangOpts,TokenKey Flag)136bdd1243dSDimitry Andric static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
137bdd1243dSDimitry Andric TokenKey Flag) {
138bdd1243dSDimitry Andric // Flag is a single bit version of TokenKey (that is, not
139bdd1243dSDimitry Andric // KEYALL/KEYALLCXX/etc), so we can check with == throughout this function.
140bdd1243dSDimitry Andric assert((Flag & ~(Flag - 1)) == Flag && "Multiple bits set?");
141bdd1243dSDimitry Andric
142bdd1243dSDimitry Andric switch (Flag) {
143bdd1243dSDimitry Andric case KEYC99:
144bdd1243dSDimitry Andric if (LangOpts.C99)
145bdd1243dSDimitry Andric return KS_Enabled;
146bdd1243dSDimitry Andric return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
1475f757f3fSDimitry Andric case KEYC23:
1485f757f3fSDimitry Andric if (LangOpts.C23)
149bdd1243dSDimitry Andric return KS_Enabled;
150bdd1243dSDimitry Andric return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
151bdd1243dSDimitry Andric case KEYCXX:
152bdd1243dSDimitry Andric return LangOpts.CPlusPlus ? KS_Enabled : KS_Unknown;
153bdd1243dSDimitry Andric case KEYCXX11:
154bdd1243dSDimitry Andric if (LangOpts.CPlusPlus11)
155bdd1243dSDimitry Andric return KS_Enabled;
156bdd1243dSDimitry Andric return LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
157bdd1243dSDimitry Andric case KEYCXX20:
158bdd1243dSDimitry Andric if (LangOpts.CPlusPlus20)
159bdd1243dSDimitry Andric return KS_Enabled;
160bdd1243dSDimitry Andric return LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
161bdd1243dSDimitry Andric case KEYGNU:
162bdd1243dSDimitry Andric return LangOpts.GNUKeywords ? KS_Extension : KS_Unknown;
163bdd1243dSDimitry Andric case KEYMS:
164bdd1243dSDimitry Andric return LangOpts.MicrosoftExt ? KS_Extension : KS_Unknown;
165bdd1243dSDimitry Andric case BOOLSUPPORT:
166bdd1243dSDimitry Andric if (LangOpts.Bool) return KS_Enabled;
167bdd1243dSDimitry Andric return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
168bdd1243dSDimitry Andric case KEYALTIVEC:
169bdd1243dSDimitry Andric return LangOpts.AltiVec ? KS_Enabled : KS_Unknown;
170bdd1243dSDimitry Andric case KEYBORLAND:
171bdd1243dSDimitry Andric return LangOpts.Borland ? KS_Extension : KS_Unknown;
172bdd1243dSDimitry Andric case KEYOPENCLC:
173bdd1243dSDimitry Andric return LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus ? KS_Enabled
174bdd1243dSDimitry Andric : KS_Unknown;
175bdd1243dSDimitry Andric case WCHARSUPPORT:
176bdd1243dSDimitry Andric return LangOpts.WChar ? KS_Enabled : KS_Unknown;
177bdd1243dSDimitry Andric case HALFSUPPORT:
178bdd1243dSDimitry Andric return LangOpts.Half ? KS_Enabled : KS_Unknown;
179bdd1243dSDimitry Andric case CHAR8SUPPORT:
180bdd1243dSDimitry Andric if (LangOpts.Char8) return KS_Enabled;
181bdd1243dSDimitry Andric if (LangOpts.CPlusPlus20) return KS_Unknown;
182bdd1243dSDimitry Andric if (LangOpts.CPlusPlus) return KS_Future;
183bdd1243dSDimitry Andric return KS_Unknown;
184bdd1243dSDimitry Andric case KEYOBJC:
185bdd1243dSDimitry Andric // We treat bridge casts as objective-C keywords so we can warn on them
186bdd1243dSDimitry Andric // in non-arc mode.
187bdd1243dSDimitry Andric return LangOpts.ObjC ? KS_Enabled : KS_Unknown;
188bdd1243dSDimitry Andric case KEYZVECTOR:
189bdd1243dSDimitry Andric return LangOpts.ZVector ? KS_Enabled : KS_Unknown;
190bdd1243dSDimitry Andric case KEYCOROUTINES:
191bdd1243dSDimitry Andric return LangOpts.Coroutines ? KS_Enabled : KS_Unknown;
192bdd1243dSDimitry Andric case KEYMODULES:
19306c3fb27SDimitry Andric return KS_Unknown;
194bdd1243dSDimitry Andric case KEYOPENCLCXX:
195bdd1243dSDimitry Andric return LangOpts.OpenCLCPlusPlus ? KS_Enabled : KS_Unknown;
196bdd1243dSDimitry Andric case KEYMSCOMPAT:
197bdd1243dSDimitry Andric return LangOpts.MSVCCompat ? KS_Enabled : KS_Unknown;
198bdd1243dSDimitry Andric case KEYSYCL:
199bdd1243dSDimitry Andric return LangOpts.isSYCL() ? KS_Enabled : KS_Unknown;
200bdd1243dSDimitry Andric case KEYCUDA:
201bdd1243dSDimitry Andric return LangOpts.CUDA ? KS_Enabled : KS_Unknown;
202bdd1243dSDimitry Andric case KEYHLSL:
203bdd1243dSDimitry Andric return LangOpts.HLSL ? KS_Enabled : KS_Unknown;
204bdd1243dSDimitry Andric case KEYNOCXX:
205bdd1243dSDimitry Andric // This is enabled in all non-C++ modes, but might be enabled for other
206bdd1243dSDimitry Andric // reasons as well.
207bdd1243dSDimitry Andric return LangOpts.CPlusPlus ? KS_Unknown : KS_Enabled;
208bdd1243dSDimitry Andric case KEYNOOPENCL:
209bdd1243dSDimitry Andric // The disable behavior for this is handled in getKeywordStatus.
210bdd1243dSDimitry Andric return KS_Unknown;
211bdd1243dSDimitry Andric case KEYNOMS18:
212bdd1243dSDimitry Andric // The disable behavior for this is handled in getKeywordStatus.
213bdd1243dSDimitry Andric return KS_Unknown;
2145f757f3fSDimitry Andric case KEYFIXEDPOINT:
2155f757f3fSDimitry Andric return LangOpts.FixedPoint ? KS_Enabled : KS_Disabled;
216bdd1243dSDimitry Andric default:
217bdd1243dSDimitry Andric llvm_unreachable("Unknown KeywordStatus flag");
218bdd1243dSDimitry Andric }
219bdd1243dSDimitry Andric }
220bdd1243dSDimitry Andric
2210b57cec5SDimitry Andric /// Translates flags as specified in TokenKinds.def into keyword status
2220b57cec5SDimitry Andric /// in the given language standard.
getKeywordStatus(const LangOptions & LangOpts,unsigned Flags)2230b57cec5SDimitry Andric static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
2240b57cec5SDimitry Andric unsigned Flags) {
225bdd1243dSDimitry Andric // KEYALL means always enabled, so special case this one.
2260b57cec5SDimitry Andric if (Flags == KEYALL) return KS_Enabled;
227bdd1243dSDimitry Andric // These are tests that need to 'always win', as they are special in that they
228bdd1243dSDimitry Andric // disable based on certain conditions.
229bdd1243dSDimitry Andric if (LangOpts.OpenCL && (Flags & KEYNOOPENCL)) return KS_Disabled;
230bdd1243dSDimitry Andric if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) &&
231bdd1243dSDimitry Andric !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015))
2320b57cec5SDimitry Andric return KS_Disabled;
233bdd1243dSDimitry Andric
234bdd1243dSDimitry Andric KeywordStatus CurStatus = KS_Unknown;
235bdd1243dSDimitry Andric
236bdd1243dSDimitry Andric while (Flags != 0) {
237bdd1243dSDimitry Andric unsigned CurFlag = Flags & ~(Flags - 1);
238bdd1243dSDimitry Andric Flags = Flags & ~CurFlag;
239bdd1243dSDimitry Andric CurStatus = std::max(
240bdd1243dSDimitry Andric CurStatus,
241bdd1243dSDimitry Andric getKeywordStatusHelper(LangOpts, static_cast<TokenKey>(CurFlag)));
242bdd1243dSDimitry Andric }
243bdd1243dSDimitry Andric
244bdd1243dSDimitry Andric if (CurStatus == KS_Unknown)
245bdd1243dSDimitry Andric return KS_Disabled;
246bdd1243dSDimitry Andric return CurStatus;
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric
2490b57cec5SDimitry Andric /// AddKeyword - This method is used to associate a token ID with specific
2500b57cec5SDimitry Andric /// identifiers because they are language keywords. This causes the lexer to
2510b57cec5SDimitry Andric /// automatically map matching identifiers to specialized token codes.
AddKeyword(StringRef Keyword,tok::TokenKind TokenCode,unsigned Flags,const LangOptions & LangOpts,IdentifierTable & Table)2520b57cec5SDimitry Andric static void AddKeyword(StringRef Keyword,
2530b57cec5SDimitry Andric tok::TokenKind TokenCode, unsigned Flags,
2540b57cec5SDimitry Andric const LangOptions &LangOpts, IdentifierTable &Table) {
2550b57cec5SDimitry Andric KeywordStatus AddResult = getKeywordStatus(LangOpts, Flags);
2560b57cec5SDimitry Andric
2570b57cec5SDimitry Andric // Don't add this keyword if disabled in this language.
2580b57cec5SDimitry Andric if (AddResult == KS_Disabled) return;
2590b57cec5SDimitry Andric
2600b57cec5SDimitry Andric IdentifierInfo &Info =
2610b57cec5SDimitry Andric Table.get(Keyword, AddResult == KS_Future ? tok::identifier : TokenCode);
2620b57cec5SDimitry Andric Info.setIsExtensionToken(AddResult == KS_Extension);
2630b57cec5SDimitry Andric Info.setIsFutureCompatKeyword(AddResult == KS_Future);
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric
2660b57cec5SDimitry Andric /// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
2670b57cec5SDimitry Andric /// representations.
AddCXXOperatorKeyword(StringRef Keyword,tok::TokenKind TokenCode,IdentifierTable & Table)2680b57cec5SDimitry Andric static void AddCXXOperatorKeyword(StringRef Keyword,
2690b57cec5SDimitry Andric tok::TokenKind TokenCode,
2700b57cec5SDimitry Andric IdentifierTable &Table) {
2710b57cec5SDimitry Andric IdentifierInfo &Info = Table.get(Keyword, TokenCode);
2720b57cec5SDimitry Andric Info.setIsCPlusPlusOperatorKeyword();
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric
2750b57cec5SDimitry Andric /// AddObjCKeyword - Register an Objective-C \@keyword like "class" "selector"
2760b57cec5SDimitry Andric /// or "property".
AddObjCKeyword(StringRef Name,tok::ObjCKeywordKind ObjCID,IdentifierTable & Table)2770b57cec5SDimitry Andric static void AddObjCKeyword(StringRef Name,
2780b57cec5SDimitry Andric tok::ObjCKeywordKind ObjCID,
2790b57cec5SDimitry Andric IdentifierTable &Table) {
2800b57cec5SDimitry Andric Table.get(Name).setObjCKeywordID(ObjCID);
2810b57cec5SDimitry Andric }
2820b57cec5SDimitry Andric
AddNotableIdentifier(StringRef Name,tok::NotableIdentifierKind BTID,IdentifierTable & Table)283*0fca6ea1SDimitry Andric static void AddNotableIdentifier(StringRef Name,
284*0fca6ea1SDimitry Andric tok::NotableIdentifierKind BTID,
28506c3fb27SDimitry Andric IdentifierTable &Table) {
286*0fca6ea1SDimitry Andric // Don't add 'not_notable' identifier.
287*0fca6ea1SDimitry Andric if (BTID != tok::not_notable) {
28806c3fb27SDimitry Andric IdentifierInfo &Info = Table.get(Name, tok::identifier);
289*0fca6ea1SDimitry Andric Info.setNotableIdentifierID(BTID);
29006c3fb27SDimitry Andric }
29106c3fb27SDimitry Andric }
29206c3fb27SDimitry Andric
2930b57cec5SDimitry Andric /// AddKeywords - Add all keywords to the symbol table.
2940b57cec5SDimitry Andric ///
AddKeywords(const LangOptions & LangOpts)2950b57cec5SDimitry Andric void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
2960b57cec5SDimitry Andric // Add keywords and tokens for the current language.
2970b57cec5SDimitry Andric #define KEYWORD(NAME, FLAGS) \
2980b57cec5SDimitry Andric AddKeyword(StringRef(#NAME), tok::kw_ ## NAME, \
2990b57cec5SDimitry Andric FLAGS, LangOpts, *this);
3000b57cec5SDimitry Andric #define ALIAS(NAME, TOK, FLAGS) \
3010b57cec5SDimitry Andric AddKeyword(StringRef(NAME), tok::kw_ ## TOK, \
3020b57cec5SDimitry Andric FLAGS, LangOpts, *this);
3030b57cec5SDimitry Andric #define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \
3040b57cec5SDimitry Andric if (LangOpts.CXXOperatorNames) \
3050b57cec5SDimitry Andric AddCXXOperatorKeyword(StringRef(#NAME), tok::ALIAS, *this);
3060b57cec5SDimitry Andric #define OBJC_AT_KEYWORD(NAME) \
3070b57cec5SDimitry Andric if (LangOpts.ObjC) \
3080b57cec5SDimitry Andric AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this);
309*0fca6ea1SDimitry Andric #define NOTABLE_IDENTIFIER(NAME) \
310*0fca6ea1SDimitry Andric AddNotableIdentifier(StringRef(#NAME), tok::NAME, *this);
31106c3fb27SDimitry Andric
3120b57cec5SDimitry Andric #define TESTING_KEYWORD(NAME, FLAGS)
3130b57cec5SDimitry Andric #include "clang/Basic/TokenKinds.def"
3140b57cec5SDimitry Andric
3150b57cec5SDimitry Andric if (LangOpts.ParseUnknownAnytype)
3160b57cec5SDimitry Andric AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL,
3170b57cec5SDimitry Andric LangOpts, *this);
3180b57cec5SDimitry Andric
3190b57cec5SDimitry Andric if (LangOpts.DeclSpecKeyword)
3200b57cec5SDimitry Andric AddKeyword("__declspec", tok::kw___declspec, KEYALL, LangOpts, *this);
3210b57cec5SDimitry Andric
322fe6060f1SDimitry Andric if (LangOpts.IEEE128)
323fe6060f1SDimitry Andric AddKeyword("__ieee128", tok::kw___float128, KEYALL, LangOpts, *this);
324fe6060f1SDimitry Andric
3250b57cec5SDimitry Andric // Add the 'import' contextual keyword.
3260b57cec5SDimitry Andric get("import").setModulesImport(true);
3270b57cec5SDimitry Andric }
3280b57cec5SDimitry Andric
3290b57cec5SDimitry Andric /// Checks if the specified token kind represents a keyword in the
3300b57cec5SDimitry Andric /// specified language.
3310b57cec5SDimitry Andric /// \returns Status of the keyword in the language.
getTokenKwStatus(const LangOptions & LangOpts,tok::TokenKind K)3320b57cec5SDimitry Andric static KeywordStatus getTokenKwStatus(const LangOptions &LangOpts,
3330b57cec5SDimitry Andric tok::TokenKind K) {
3340b57cec5SDimitry Andric switch (K) {
3350b57cec5SDimitry Andric #define KEYWORD(NAME, FLAGS) \
3360b57cec5SDimitry Andric case tok::kw_##NAME: return getKeywordStatus(LangOpts, FLAGS);
3370b57cec5SDimitry Andric #include "clang/Basic/TokenKinds.def"
3380b57cec5SDimitry Andric default: return KS_Disabled;
3390b57cec5SDimitry Andric }
3400b57cec5SDimitry Andric }
3410b57cec5SDimitry Andric
3420b57cec5SDimitry Andric /// Returns true if the identifier represents a keyword in the
3430b57cec5SDimitry Andric /// specified language.
isKeyword(const LangOptions & LangOpts) const3440b57cec5SDimitry Andric bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) const {
3450b57cec5SDimitry Andric switch (getTokenKwStatus(LangOpts, getTokenID())) {
3460b57cec5SDimitry Andric case KS_Enabled:
3470b57cec5SDimitry Andric case KS_Extension:
3480b57cec5SDimitry Andric return true;
3490b57cec5SDimitry Andric default:
3500b57cec5SDimitry Andric return false;
3510b57cec5SDimitry Andric }
3520b57cec5SDimitry Andric }
3530b57cec5SDimitry Andric
3540b57cec5SDimitry Andric /// Returns true if the identifier represents a C++ keyword in the
3550b57cec5SDimitry Andric /// specified language.
isCPlusPlusKeyword(const LangOptions & LangOpts) const3560b57cec5SDimitry Andric bool IdentifierInfo::isCPlusPlusKeyword(const LangOptions &LangOpts) const {
3570b57cec5SDimitry Andric if (!LangOpts.CPlusPlus || !isKeyword(LangOpts))
3580b57cec5SDimitry Andric return false;
3590b57cec5SDimitry Andric // This is a C++ keyword if this identifier is not a keyword when checked
3600b57cec5SDimitry Andric // using LangOptions without C++ support.
3610b57cec5SDimitry Andric LangOptions LangOptsNoCPP = LangOpts;
3620b57cec5SDimitry Andric LangOptsNoCPP.CPlusPlus = false;
3630b57cec5SDimitry Andric LangOptsNoCPP.CPlusPlus11 = false;
3645ffd83dbSDimitry Andric LangOptsNoCPP.CPlusPlus20 = false;
3650b57cec5SDimitry Andric return !isKeyword(LangOptsNoCPP);
3660b57cec5SDimitry Andric }
3670b57cec5SDimitry Andric
368fe6060f1SDimitry Andric ReservedIdentifierStatus
isReserved(const LangOptions & LangOpts) const369fe6060f1SDimitry Andric IdentifierInfo::isReserved(const LangOptions &LangOpts) const {
370fe6060f1SDimitry Andric StringRef Name = getName();
371fe6060f1SDimitry Andric
372fe6060f1SDimitry Andric // '_' is a reserved identifier, but its use is so common (e.g. to store
373fe6060f1SDimitry Andric // ignored values) that we don't warn on it.
374fe6060f1SDimitry Andric if (Name.size() <= 1)
375fe6060f1SDimitry Andric return ReservedIdentifierStatus::NotReserved;
376fe6060f1SDimitry Andric
377fe6060f1SDimitry Andric // [lex.name] p3
378fe6060f1SDimitry Andric if (Name[0] == '_') {
379fe6060f1SDimitry Andric
380fe6060f1SDimitry Andric // Each name that begins with an underscore followed by an uppercase letter
381fe6060f1SDimitry Andric // or another underscore is reserved.
382fe6060f1SDimitry Andric if (Name[1] == '_')
383fe6060f1SDimitry Andric return ReservedIdentifierStatus::StartsWithDoubleUnderscore;
384fe6060f1SDimitry Andric
385fe6060f1SDimitry Andric if ('A' <= Name[1] && Name[1] <= 'Z')
386fe6060f1SDimitry Andric return ReservedIdentifierStatus::
387fe6060f1SDimitry Andric StartsWithUnderscoreFollowedByCapitalLetter;
388fe6060f1SDimitry Andric
389fe6060f1SDimitry Andric // This is a bit misleading: it actually means it's only reserved if we're
390fe6060f1SDimitry Andric // at global scope because it starts with an underscore.
391fe6060f1SDimitry Andric return ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope;
392fe6060f1SDimitry Andric }
393fe6060f1SDimitry Andric
394fe6060f1SDimitry Andric // Each name that contains a double underscore (__) is reserved.
395fe6060f1SDimitry Andric if (LangOpts.CPlusPlus && Name.contains("__"))
396fe6060f1SDimitry Andric return ReservedIdentifierStatus::ContainsDoubleUnderscore;
397fe6060f1SDimitry Andric
398fe6060f1SDimitry Andric return ReservedIdentifierStatus::NotReserved;
399fe6060f1SDimitry Andric }
400fe6060f1SDimitry Andric
40106c3fb27SDimitry Andric ReservedLiteralSuffixIdStatus
isReservedLiteralSuffixId() const40206c3fb27SDimitry Andric IdentifierInfo::isReservedLiteralSuffixId() const {
40306c3fb27SDimitry Andric StringRef Name = getName();
40406c3fb27SDimitry Andric
40506c3fb27SDimitry Andric if (Name[0] != '_')
40606c3fb27SDimitry Andric return ReservedLiteralSuffixIdStatus::NotStartsWithUnderscore;
40706c3fb27SDimitry Andric
40806c3fb27SDimitry Andric if (Name.contains("__"))
40906c3fb27SDimitry Andric return ReservedLiteralSuffixIdStatus::ContainsDoubleUnderscore;
41006c3fb27SDimitry Andric
41106c3fb27SDimitry Andric return ReservedLiteralSuffixIdStatus::NotReserved;
41206c3fb27SDimitry Andric }
41306c3fb27SDimitry Andric
deuglifiedName() const41404eeddc0SDimitry Andric StringRef IdentifierInfo::deuglifiedName() const {
41504eeddc0SDimitry Andric StringRef Name = getName();
41604eeddc0SDimitry Andric if (Name.size() >= 2 && Name.front() == '_' &&
41704eeddc0SDimitry Andric (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')))
41804eeddc0SDimitry Andric return Name.ltrim('_');
41904eeddc0SDimitry Andric return Name;
42004eeddc0SDimitry Andric }
42104eeddc0SDimitry Andric
getPPKeywordID() const4220b57cec5SDimitry Andric tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
4230b57cec5SDimitry Andric // We use a perfect hash function here involving the length of the keyword,
4240b57cec5SDimitry Andric // the first and third character. For preprocessor ID's there are no
4250b57cec5SDimitry Andric // collisions (if there were, the switch below would complain about duplicate
4260b57cec5SDimitry Andric // case values). Note that this depends on 'if' being null terminated.
4270b57cec5SDimitry Andric
4280b57cec5SDimitry Andric #define HASH(LEN, FIRST, THIRD) \
429*0fca6ea1SDimitry Andric (LEN << 6) + (((FIRST - 'a') - (THIRD - 'a')) & 63)
4300b57cec5SDimitry Andric #define CASE(LEN, FIRST, THIRD, NAME) \
4310b57cec5SDimitry Andric case HASH(LEN, FIRST, THIRD): \
4320b57cec5SDimitry Andric return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME
4330b57cec5SDimitry Andric
4340b57cec5SDimitry Andric unsigned Len = getLength();
4350b57cec5SDimitry Andric if (Len < 2) return tok::pp_not_keyword;
4360b57cec5SDimitry Andric const char *Name = getNameStart();
4370b57cec5SDimitry Andric switch (HASH(Len, Name[0], Name[2])) {
4380b57cec5SDimitry Andric default: return tok::pp_not_keyword;
4390b57cec5SDimitry Andric CASE( 2, 'i', '\0', if);
4400b57cec5SDimitry Andric CASE( 4, 'e', 'i', elif);
4410b57cec5SDimitry Andric CASE( 4, 'e', 's', else);
4420b57cec5SDimitry Andric CASE( 4, 'l', 'n', line);
4430b57cec5SDimitry Andric CASE( 4, 's', 'c', sccs);
444*0fca6ea1SDimitry Andric CASE( 5, 'e', 'b', embed);
4450b57cec5SDimitry Andric CASE( 5, 'e', 'd', endif);
4460b57cec5SDimitry Andric CASE( 5, 'e', 'r', error);
4470b57cec5SDimitry Andric CASE( 5, 'i', 'e', ident);
4480b57cec5SDimitry Andric CASE( 5, 'i', 'd', ifdef);
4490b57cec5SDimitry Andric CASE( 5, 'u', 'd', undef);
4500b57cec5SDimitry Andric
4510b57cec5SDimitry Andric CASE( 6, 'a', 's', assert);
4520b57cec5SDimitry Andric CASE( 6, 'd', 'f', define);
4530b57cec5SDimitry Andric CASE( 6, 'i', 'n', ifndef);
4540b57cec5SDimitry Andric CASE( 6, 'i', 'p', import);
4550b57cec5SDimitry Andric CASE( 6, 'p', 'a', pragma);
4560b57cec5SDimitry Andric
4570b57cec5SDimitry Andric CASE( 7, 'd', 'f', defined);
458fe6060f1SDimitry Andric CASE( 7, 'e', 'i', elifdef);
4590b57cec5SDimitry Andric CASE( 7, 'i', 'c', include);
4600b57cec5SDimitry Andric CASE( 7, 'w', 'r', warning);
4610b57cec5SDimitry Andric
462fe6060f1SDimitry Andric CASE( 8, 'e', 'i', elifndef);
4630b57cec5SDimitry Andric CASE( 8, 'u', 'a', unassert);
4640b57cec5SDimitry Andric CASE(12, 'i', 'c', include_next);
4650b57cec5SDimitry Andric
4660b57cec5SDimitry Andric CASE(14, '_', 'p', __public_macro);
4670b57cec5SDimitry Andric
4680b57cec5SDimitry Andric CASE(15, '_', 'p', __private_macro);
4690b57cec5SDimitry Andric
4700b57cec5SDimitry Andric CASE(16, '_', 'i', __include_macros);
4710b57cec5SDimitry Andric #undef CASE
4720b57cec5SDimitry Andric #undef HASH
4730b57cec5SDimitry Andric }
4740b57cec5SDimitry Andric }
4750b57cec5SDimitry Andric
4760b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4770b57cec5SDimitry Andric // Stats Implementation
4780b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4790b57cec5SDimitry Andric
4800b57cec5SDimitry Andric /// PrintStats - Print statistics about how well the identifier table is doing
4810b57cec5SDimitry Andric /// at hashing identifiers.
PrintStats() const4820b57cec5SDimitry Andric void IdentifierTable::PrintStats() const {
4830b57cec5SDimitry Andric unsigned NumBuckets = HashTable.getNumBuckets();
4840b57cec5SDimitry Andric unsigned NumIdentifiers = HashTable.getNumItems();
4850b57cec5SDimitry Andric unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers;
4860b57cec5SDimitry Andric unsigned AverageIdentifierSize = 0;
4870b57cec5SDimitry Andric unsigned MaxIdentifierLength = 0;
4880b57cec5SDimitry Andric
4890b57cec5SDimitry Andric // TODO: Figure out maximum times an identifier had to probe for -stats.
4900b57cec5SDimitry Andric for (llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator>::const_iterator
4910b57cec5SDimitry Andric I = HashTable.begin(), E = HashTable.end(); I != E; ++I) {
4920b57cec5SDimitry Andric unsigned IdLen = I->getKeyLength();
4930b57cec5SDimitry Andric AverageIdentifierSize += IdLen;
4940b57cec5SDimitry Andric if (MaxIdentifierLength < IdLen)
4950b57cec5SDimitry Andric MaxIdentifierLength = IdLen;
4960b57cec5SDimitry Andric }
4970b57cec5SDimitry Andric
4980b57cec5SDimitry Andric fprintf(stderr, "\n*** Identifier Table Stats:\n");
4990b57cec5SDimitry Andric fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers);
5000b57cec5SDimitry Andric fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets);
5010b57cec5SDimitry Andric fprintf(stderr, "Hash density (#identifiers per bucket): %f\n",
5020b57cec5SDimitry Andric NumIdentifiers/(double)NumBuckets);
5030b57cec5SDimitry Andric fprintf(stderr, "Ave identifier length: %f\n",
5040b57cec5SDimitry Andric (AverageIdentifierSize/(double)NumIdentifiers));
5050b57cec5SDimitry Andric fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength);
5060b57cec5SDimitry Andric
5070b57cec5SDimitry Andric // Compute statistics about the memory allocated for identifiers.
5080b57cec5SDimitry Andric HashTable.getAllocator().PrintStats();
5090b57cec5SDimitry Andric }
5100b57cec5SDimitry Andric
5110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5120b57cec5SDimitry Andric // SelectorTable Implementation
5130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5140b57cec5SDimitry Andric
getHashValue(clang::Selector S)5150b57cec5SDimitry Andric unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) {
5160b57cec5SDimitry Andric return DenseMapInfo<void*>::getHashValue(S.getAsOpaquePtr());
5170b57cec5SDimitry Andric }
5180b57cec5SDimitry Andric
isKeywordSelector(ArrayRef<StringRef> Names) const519a7dea167SDimitry Andric bool Selector::isKeywordSelector(ArrayRef<StringRef> Names) const {
520a7dea167SDimitry Andric assert(!Names.empty() && "must have >= 1 selector slots");
521a7dea167SDimitry Andric if (getNumArgs() != Names.size())
522a7dea167SDimitry Andric return false;
523a7dea167SDimitry Andric for (unsigned I = 0, E = Names.size(); I != E; ++I) {
524a7dea167SDimitry Andric if (getNameForSlot(I) != Names[I])
525a7dea167SDimitry Andric return false;
526a7dea167SDimitry Andric }
527a7dea167SDimitry Andric return true;
528a7dea167SDimitry Andric }
529a7dea167SDimitry Andric
isUnarySelector(StringRef Name) const530a7dea167SDimitry Andric bool Selector::isUnarySelector(StringRef Name) const {
531a7dea167SDimitry Andric return isUnarySelector() && getNameForSlot(0) == Name;
532a7dea167SDimitry Andric }
533a7dea167SDimitry Andric
getNumArgs() const5340b57cec5SDimitry Andric unsigned Selector::getNumArgs() const {
5350b57cec5SDimitry Andric unsigned IIF = getIdentifierInfoFlag();
5360b57cec5SDimitry Andric if (IIF <= ZeroArg)
5370b57cec5SDimitry Andric return 0;
5380b57cec5SDimitry Andric if (IIF == OneArg)
5390b57cec5SDimitry Andric return 1;
5400b57cec5SDimitry Andric // We point to a MultiKeywordSelector.
5410b57cec5SDimitry Andric MultiKeywordSelector *SI = getMultiKeywordSelector();
5420b57cec5SDimitry Andric return SI->getNumArgs();
5430b57cec5SDimitry Andric }
5440b57cec5SDimitry Andric
545*0fca6ea1SDimitry Andric const IdentifierInfo *
getIdentifierInfoForSlot(unsigned argIndex) const546*0fca6ea1SDimitry Andric Selector::getIdentifierInfoForSlot(unsigned argIndex) const {
5470b57cec5SDimitry Andric if (getIdentifierInfoFlag() < MultiArg) {
5480b57cec5SDimitry Andric assert(argIndex == 0 && "illegal keyword index");
5490b57cec5SDimitry Andric return getAsIdentifierInfo();
5500b57cec5SDimitry Andric }
5510b57cec5SDimitry Andric
5520b57cec5SDimitry Andric // We point to a MultiKeywordSelector.
5530b57cec5SDimitry Andric MultiKeywordSelector *SI = getMultiKeywordSelector();
5540b57cec5SDimitry Andric return SI->getIdentifierInfoForSlot(argIndex);
5550b57cec5SDimitry Andric }
5560b57cec5SDimitry Andric
getNameForSlot(unsigned int argIndex) const5570b57cec5SDimitry Andric StringRef Selector::getNameForSlot(unsigned int argIndex) const {
558*0fca6ea1SDimitry Andric const IdentifierInfo *II = getIdentifierInfoForSlot(argIndex);
5590b57cec5SDimitry Andric return II ? II->getName() : StringRef();
5600b57cec5SDimitry Andric }
5610b57cec5SDimitry Andric
getName() const5620b57cec5SDimitry Andric std::string MultiKeywordSelector::getName() const {
5630b57cec5SDimitry Andric SmallString<256> Str;
5640b57cec5SDimitry Andric llvm::raw_svector_ostream OS(Str);
5650b57cec5SDimitry Andric for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) {
5660b57cec5SDimitry Andric if (*I)
5670b57cec5SDimitry Andric OS << (*I)->getName();
5680b57cec5SDimitry Andric OS << ':';
5690b57cec5SDimitry Andric }
5700b57cec5SDimitry Andric
5715ffd83dbSDimitry Andric return std::string(OS.str());
5720b57cec5SDimitry Andric }
5730b57cec5SDimitry Andric
getAsString() const5740b57cec5SDimitry Andric std::string Selector::getAsString() const {
5755f757f3fSDimitry Andric if (isNull())
5760b57cec5SDimitry Andric return "<null selector>";
5770b57cec5SDimitry Andric
5780b57cec5SDimitry Andric if (getIdentifierInfoFlag() < MultiArg) {
579*0fca6ea1SDimitry Andric const IdentifierInfo *II = getAsIdentifierInfo();
5800b57cec5SDimitry Andric
5810b57cec5SDimitry Andric if (getNumArgs() == 0) {
5820b57cec5SDimitry Andric assert(II && "If the number of arguments is 0 then II is guaranteed to "
5830b57cec5SDimitry Andric "not be null.");
5845ffd83dbSDimitry Andric return std::string(II->getName());
5850b57cec5SDimitry Andric }
5860b57cec5SDimitry Andric
5870b57cec5SDimitry Andric if (!II)
5880b57cec5SDimitry Andric return ":";
5890b57cec5SDimitry Andric
5900b57cec5SDimitry Andric return II->getName().str() + ":";
5910b57cec5SDimitry Andric }
5920b57cec5SDimitry Andric
5930b57cec5SDimitry Andric // We have a multiple keyword selector.
5940b57cec5SDimitry Andric return getMultiKeywordSelector()->getName();
5950b57cec5SDimitry Andric }
5960b57cec5SDimitry Andric
print(llvm::raw_ostream & OS) const5970b57cec5SDimitry Andric void Selector::print(llvm::raw_ostream &OS) const {
5980b57cec5SDimitry Andric OS << getAsString();
5990b57cec5SDimitry Andric }
6000b57cec5SDimitry Andric
dump() const6010b57cec5SDimitry Andric LLVM_DUMP_METHOD void Selector::dump() const { print(llvm::errs()); }
6020b57cec5SDimitry Andric
6030b57cec5SDimitry Andric /// Interpreting the given string using the normal CamelCase
6040b57cec5SDimitry Andric /// conventions, determine whether the given string starts with the
6050b57cec5SDimitry Andric /// given "word", which is assumed to end in a lowercase letter.
startsWithWord(StringRef name,StringRef word)6060b57cec5SDimitry Andric static bool startsWithWord(StringRef name, StringRef word) {
6070b57cec5SDimitry Andric if (name.size() < word.size()) return false;
6080b57cec5SDimitry Andric return ((name.size() == word.size() || !isLowercase(name[word.size()])) &&
6095f757f3fSDimitry Andric name.starts_with(word));
6100b57cec5SDimitry Andric }
6110b57cec5SDimitry Andric
getMethodFamilyImpl(Selector sel)6120b57cec5SDimitry Andric ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
613*0fca6ea1SDimitry Andric const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
6140b57cec5SDimitry Andric if (!first) return OMF_None;
6150b57cec5SDimitry Andric
6160b57cec5SDimitry Andric StringRef name = first->getName();
6170b57cec5SDimitry Andric if (sel.isUnarySelector()) {
6180b57cec5SDimitry Andric if (name == "autorelease") return OMF_autorelease;
6190b57cec5SDimitry Andric if (name == "dealloc") return OMF_dealloc;
6200b57cec5SDimitry Andric if (name == "finalize") return OMF_finalize;
6210b57cec5SDimitry Andric if (name == "release") return OMF_release;
6220b57cec5SDimitry Andric if (name == "retain") return OMF_retain;
6230b57cec5SDimitry Andric if (name == "retainCount") return OMF_retainCount;
6240b57cec5SDimitry Andric if (name == "self") return OMF_self;
6250b57cec5SDimitry Andric if (name == "initialize") return OMF_initialize;
6260b57cec5SDimitry Andric }
6270b57cec5SDimitry Andric
6280b57cec5SDimitry Andric if (name == "performSelector" || name == "performSelectorInBackground" ||
6290b57cec5SDimitry Andric name == "performSelectorOnMainThread")
6300b57cec5SDimitry Andric return OMF_performSelector;
6310b57cec5SDimitry Andric
6320b57cec5SDimitry Andric // The other method families may begin with a prefix of underscores.
633647cbc5dSDimitry Andric name = name.ltrim('_');
6340b57cec5SDimitry Andric
6350b57cec5SDimitry Andric if (name.empty()) return OMF_None;
6360b57cec5SDimitry Andric switch (name.front()) {
6370b57cec5SDimitry Andric case 'a':
6380b57cec5SDimitry Andric if (startsWithWord(name, "alloc")) return OMF_alloc;
6390b57cec5SDimitry Andric break;
6400b57cec5SDimitry Andric case 'c':
6410b57cec5SDimitry Andric if (startsWithWord(name, "copy")) return OMF_copy;
6420b57cec5SDimitry Andric break;
6430b57cec5SDimitry Andric case 'i':
6440b57cec5SDimitry Andric if (startsWithWord(name, "init")) return OMF_init;
6450b57cec5SDimitry Andric break;
6460b57cec5SDimitry Andric case 'm':
6470b57cec5SDimitry Andric if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy;
6480b57cec5SDimitry Andric break;
6490b57cec5SDimitry Andric case 'n':
6500b57cec5SDimitry Andric if (startsWithWord(name, "new")) return OMF_new;
6510b57cec5SDimitry Andric break;
6520b57cec5SDimitry Andric default:
6530b57cec5SDimitry Andric break;
6540b57cec5SDimitry Andric }
6550b57cec5SDimitry Andric
6560b57cec5SDimitry Andric return OMF_None;
6570b57cec5SDimitry Andric }
6580b57cec5SDimitry Andric
getInstTypeMethodFamily(Selector sel)6590b57cec5SDimitry Andric ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) {
660*0fca6ea1SDimitry Andric const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
6610b57cec5SDimitry Andric if (!first) return OIT_None;
6620b57cec5SDimitry Andric
6630b57cec5SDimitry Andric StringRef name = first->getName();
6640b57cec5SDimitry Andric
6650b57cec5SDimitry Andric if (name.empty()) return OIT_None;
6660b57cec5SDimitry Andric switch (name.front()) {
6670b57cec5SDimitry Andric case 'a':
6680b57cec5SDimitry Andric if (startsWithWord(name, "array")) return OIT_Array;
6690b57cec5SDimitry Andric break;
6700b57cec5SDimitry Andric case 'd':
6710b57cec5SDimitry Andric if (startsWithWord(name, "default")) return OIT_ReturnsSelf;
6720b57cec5SDimitry Andric if (startsWithWord(name, "dictionary")) return OIT_Dictionary;
6730b57cec5SDimitry Andric break;
6740b57cec5SDimitry Andric case 's':
6750b57cec5SDimitry Andric if (startsWithWord(name, "shared")) return OIT_ReturnsSelf;
6760b57cec5SDimitry Andric if (startsWithWord(name, "standard")) return OIT_Singleton;
6770b57cec5SDimitry Andric break;
6780b57cec5SDimitry Andric case 'i':
6790b57cec5SDimitry Andric if (startsWithWord(name, "init")) return OIT_Init;
6800b57cec5SDimitry Andric break;
6810b57cec5SDimitry Andric default:
6820b57cec5SDimitry Andric break;
6830b57cec5SDimitry Andric }
6840b57cec5SDimitry Andric return OIT_None;
6850b57cec5SDimitry Andric }
6860b57cec5SDimitry Andric
getStringFormatFamilyImpl(Selector sel)6870b57cec5SDimitry Andric ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) {
688*0fca6ea1SDimitry Andric const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
6890b57cec5SDimitry Andric if (!first) return SFF_None;
6900b57cec5SDimitry Andric
6910b57cec5SDimitry Andric StringRef name = first->getName();
6920b57cec5SDimitry Andric
6930b57cec5SDimitry Andric switch (name.front()) {
6940b57cec5SDimitry Andric case 'a':
6950b57cec5SDimitry Andric if (name == "appendFormat") return SFF_NSString;
6960b57cec5SDimitry Andric break;
6970b57cec5SDimitry Andric
6980b57cec5SDimitry Andric case 'i':
6990b57cec5SDimitry Andric if (name == "initWithFormat") return SFF_NSString;
7000b57cec5SDimitry Andric break;
7010b57cec5SDimitry Andric
7020b57cec5SDimitry Andric case 'l':
7030b57cec5SDimitry Andric if (name == "localizedStringWithFormat") return SFF_NSString;
7040b57cec5SDimitry Andric break;
7050b57cec5SDimitry Andric
7060b57cec5SDimitry Andric case 's':
7070b57cec5SDimitry Andric if (name == "stringByAppendingFormat" ||
7080b57cec5SDimitry Andric name == "stringWithFormat") return SFF_NSString;
7090b57cec5SDimitry Andric break;
7100b57cec5SDimitry Andric }
7110b57cec5SDimitry Andric return SFF_None;
7120b57cec5SDimitry Andric }
7130b57cec5SDimitry Andric
7140b57cec5SDimitry Andric namespace {
7150b57cec5SDimitry Andric
7160b57cec5SDimitry Andric struct SelectorTableImpl {
7170b57cec5SDimitry Andric llvm::FoldingSet<MultiKeywordSelector> Table;
7180b57cec5SDimitry Andric llvm::BumpPtrAllocator Allocator;
7190b57cec5SDimitry Andric };
7200b57cec5SDimitry Andric
7210b57cec5SDimitry Andric } // namespace
7220b57cec5SDimitry Andric
getSelectorTableImpl(void * P)7230b57cec5SDimitry Andric static SelectorTableImpl &getSelectorTableImpl(void *P) {
7240b57cec5SDimitry Andric return *static_cast<SelectorTableImpl*>(P);
7250b57cec5SDimitry Andric }
7260b57cec5SDimitry Andric
7270b57cec5SDimitry Andric SmallString<64>
constructSetterName(StringRef Name)7280b57cec5SDimitry Andric SelectorTable::constructSetterName(StringRef Name) {
7290b57cec5SDimitry Andric SmallString<64> SetterName("set");
7300b57cec5SDimitry Andric SetterName += Name;
7310b57cec5SDimitry Andric SetterName[3] = toUppercase(SetterName[3]);
7320b57cec5SDimitry Andric return SetterName;
7330b57cec5SDimitry Andric }
7340b57cec5SDimitry Andric
7350b57cec5SDimitry Andric Selector
constructSetterSelector(IdentifierTable & Idents,SelectorTable & SelTable,const IdentifierInfo * Name)7360b57cec5SDimitry Andric SelectorTable::constructSetterSelector(IdentifierTable &Idents,
7370b57cec5SDimitry Andric SelectorTable &SelTable,
7380b57cec5SDimitry Andric const IdentifierInfo *Name) {
7390b57cec5SDimitry Andric IdentifierInfo *SetterName =
7400b57cec5SDimitry Andric &Idents.get(constructSetterName(Name->getName()));
7410b57cec5SDimitry Andric return SelTable.getUnarySelector(SetterName);
7420b57cec5SDimitry Andric }
7430b57cec5SDimitry Andric
getPropertyNameFromSetterSelector(Selector Sel)7440b57cec5SDimitry Andric std::string SelectorTable::getPropertyNameFromSetterSelector(Selector Sel) {
7450b57cec5SDimitry Andric StringRef Name = Sel.getNameForSlot(0);
7465f757f3fSDimitry Andric assert(Name.starts_with("set") && "invalid setter name");
7470b57cec5SDimitry Andric return (Twine(toLowercase(Name[3])) + Name.drop_front(4)).str();
7480b57cec5SDimitry Andric }
7490b57cec5SDimitry Andric
getTotalMemory() const7500b57cec5SDimitry Andric size_t SelectorTable::getTotalMemory() const {
7510b57cec5SDimitry Andric SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
7520b57cec5SDimitry Andric return SelTabImpl.Allocator.getTotalMemory();
7530b57cec5SDimitry Andric }
7540b57cec5SDimitry Andric
getSelector(unsigned nKeys,const IdentifierInfo ** IIV)755*0fca6ea1SDimitry Andric Selector SelectorTable::getSelector(unsigned nKeys,
756*0fca6ea1SDimitry Andric const IdentifierInfo **IIV) {
7570b57cec5SDimitry Andric if (nKeys < 2)
7580b57cec5SDimitry Andric return Selector(IIV[0], nKeys);
7590b57cec5SDimitry Andric
7600b57cec5SDimitry Andric SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
7610b57cec5SDimitry Andric
7620b57cec5SDimitry Andric // Unique selector, to guarantee there is one per name.
7630b57cec5SDimitry Andric llvm::FoldingSetNodeID ID;
7640b57cec5SDimitry Andric MultiKeywordSelector::Profile(ID, IIV, nKeys);
7650b57cec5SDimitry Andric
7660b57cec5SDimitry Andric void *InsertPos = nullptr;
7670b57cec5SDimitry Andric if (MultiKeywordSelector *SI =
7680b57cec5SDimitry Andric SelTabImpl.Table.FindNodeOrInsertPos(ID, InsertPos))
7690b57cec5SDimitry Andric return Selector(SI);
7700b57cec5SDimitry Andric
7710b57cec5SDimitry Andric // MultiKeywordSelector objects are not allocated with new because they have a
7720b57cec5SDimitry Andric // variable size array (for parameter types) at the end of them.
7730b57cec5SDimitry Andric unsigned Size = sizeof(MultiKeywordSelector) + nKeys*sizeof(IdentifierInfo *);
7740b57cec5SDimitry Andric MultiKeywordSelector *SI =
7750b57cec5SDimitry Andric (MultiKeywordSelector *)SelTabImpl.Allocator.Allocate(
7760b57cec5SDimitry Andric Size, alignof(MultiKeywordSelector));
7770b57cec5SDimitry Andric new (SI) MultiKeywordSelector(nKeys, IIV);
7780b57cec5SDimitry Andric SelTabImpl.Table.InsertNode(SI, InsertPos);
7790b57cec5SDimitry Andric return Selector(SI);
7800b57cec5SDimitry Andric }
7810b57cec5SDimitry Andric
SelectorTable()7820b57cec5SDimitry Andric SelectorTable::SelectorTable() {
7830b57cec5SDimitry Andric Impl = new SelectorTableImpl();
7840b57cec5SDimitry Andric }
7850b57cec5SDimitry Andric
~SelectorTable()7860b57cec5SDimitry Andric SelectorTable::~SelectorTable() {
7870b57cec5SDimitry Andric delete &getSelectorTableImpl(Impl);
7880b57cec5SDimitry Andric }
7890b57cec5SDimitry Andric
getOperatorSpelling(OverloadedOperatorKind Operator)7900b57cec5SDimitry Andric const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) {
7910b57cec5SDimitry Andric switch (Operator) {
7920b57cec5SDimitry Andric case OO_None:
7930b57cec5SDimitry Andric case NUM_OVERLOADED_OPERATORS:
7940b57cec5SDimitry Andric return nullptr;
7950b57cec5SDimitry Andric
7960b57cec5SDimitry Andric #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
7970b57cec5SDimitry Andric case OO_##Name: return Spelling;
7980b57cec5SDimitry Andric #include "clang/Basic/OperatorKinds.def"
7990b57cec5SDimitry Andric }
8000b57cec5SDimitry Andric
8010b57cec5SDimitry Andric llvm_unreachable("Invalid OverloadedOperatorKind!");
8020b57cec5SDimitry Andric }
8030b57cec5SDimitry Andric
getNullabilitySpelling(NullabilityKind kind,bool isContextSensitive)8040b57cec5SDimitry Andric StringRef clang::getNullabilitySpelling(NullabilityKind kind,
8050b57cec5SDimitry Andric bool isContextSensitive) {
8060b57cec5SDimitry Andric switch (kind) {
8070b57cec5SDimitry Andric case NullabilityKind::NonNull:
8080b57cec5SDimitry Andric return isContextSensitive ? "nonnull" : "_Nonnull";
8090b57cec5SDimitry Andric
8100b57cec5SDimitry Andric case NullabilityKind::Nullable:
8110b57cec5SDimitry Andric return isContextSensitive ? "nullable" : "_Nullable";
8120b57cec5SDimitry Andric
813e8d8bef9SDimitry Andric case NullabilityKind::NullableResult:
814e8d8bef9SDimitry Andric assert(!isContextSensitive &&
815e8d8bef9SDimitry Andric "_Nullable_result isn't supported as context-sensitive keyword");
816e8d8bef9SDimitry Andric return "_Nullable_result";
817e8d8bef9SDimitry Andric
8180b57cec5SDimitry Andric case NullabilityKind::Unspecified:
8190b57cec5SDimitry Andric return isContextSensitive ? "null_unspecified" : "_Null_unspecified";
8200b57cec5SDimitry Andric }
8210b57cec5SDimitry Andric llvm_unreachable("Unknown nullability kind.");
8220b57cec5SDimitry Andric }
823bdd1243dSDimitry Andric
operator <<(llvm::raw_ostream & OS,NullabilityKind NK)82406c3fb27SDimitry Andric llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
82506c3fb27SDimitry Andric NullabilityKind NK) {
82606c3fb27SDimitry Andric switch (NK) {
82706c3fb27SDimitry Andric case NullabilityKind::NonNull:
82806c3fb27SDimitry Andric return OS << "NonNull";
82906c3fb27SDimitry Andric case NullabilityKind::Nullable:
83006c3fb27SDimitry Andric return OS << "Nullable";
83106c3fb27SDimitry Andric case NullabilityKind::NullableResult:
83206c3fb27SDimitry Andric return OS << "NullableResult";
83306c3fb27SDimitry Andric case NullabilityKind::Unspecified:
83406c3fb27SDimitry Andric return OS << "Unspecified";
83506c3fb27SDimitry Andric }
83606c3fb27SDimitry Andric llvm_unreachable("Unknown nullability kind.");
83706c3fb27SDimitry Andric }
83806c3fb27SDimitry Andric
839bdd1243dSDimitry Andric diag::kind
getFutureCompatDiagKind(const IdentifierInfo & II,const LangOptions & LangOpts)840bdd1243dSDimitry Andric IdentifierTable::getFutureCompatDiagKind(const IdentifierInfo &II,
841bdd1243dSDimitry Andric const LangOptions &LangOpts) {
842bdd1243dSDimitry Andric assert(II.isFutureCompatKeyword() && "diagnostic should not be needed");
843bdd1243dSDimitry Andric
844bdd1243dSDimitry Andric unsigned Flags = llvm::StringSwitch<unsigned>(II.getName())
845bdd1243dSDimitry Andric #define KEYWORD(NAME, FLAGS) .Case(#NAME, FLAGS)
846bdd1243dSDimitry Andric #include "clang/Basic/TokenKinds.def"
847bdd1243dSDimitry Andric #undef KEYWORD
848bdd1243dSDimitry Andric ;
849bdd1243dSDimitry Andric
850bdd1243dSDimitry Andric if (LangOpts.CPlusPlus) {
851bdd1243dSDimitry Andric if ((Flags & KEYCXX11) == KEYCXX11)
852bdd1243dSDimitry Andric return diag::warn_cxx11_keyword;
853bdd1243dSDimitry Andric
854bdd1243dSDimitry Andric // char8_t is not modeled as a CXX20_KEYWORD because it's not
855bdd1243dSDimitry Andric // unconditionally enabled in C++20 mode. (It can be disabled
856bdd1243dSDimitry Andric // by -fno-char8_t.)
857bdd1243dSDimitry Andric if (((Flags & KEYCXX20) == KEYCXX20) ||
858bdd1243dSDimitry Andric ((Flags & CHAR8SUPPORT) == CHAR8SUPPORT))
859bdd1243dSDimitry Andric return diag::warn_cxx20_keyword;
860bdd1243dSDimitry Andric } else {
861bdd1243dSDimitry Andric if ((Flags & KEYC99) == KEYC99)
862bdd1243dSDimitry Andric return diag::warn_c99_keyword;
8635f757f3fSDimitry Andric if ((Flags & KEYC23) == KEYC23)
8645f757f3fSDimitry Andric return diag::warn_c23_keyword;
865bdd1243dSDimitry Andric }
866bdd1243dSDimitry Andric
867bdd1243dSDimitry Andric llvm_unreachable(
868bdd1243dSDimitry Andric "Keyword not known to come from a newer Standard or proposed Standard");
869bdd1243dSDimitry Andric }
870