1e5dd7070Spatrick //===- IdentifierTable.cpp - Hash table for identifier lookup -------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements the IdentifierInfo, IdentifierVisitor, and
10e5dd7070Spatrick // IdentifierTable interfaces.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick
14e5dd7070Spatrick #include "clang/Basic/IdentifierTable.h"
15e5dd7070Spatrick #include "clang/Basic/CharInfo.h"
16*12c85518Srobert #include "clang/Basic/DiagnosticLex.h"
17e5dd7070Spatrick #include "clang/Basic/LangOptions.h"
18e5dd7070Spatrick #include "clang/Basic/OperatorKinds.h"
19e5dd7070Spatrick #include "clang/Basic/Specifiers.h"
20ec727ea7Spatrick #include "clang/Basic/TargetBuiltins.h"
21e5dd7070Spatrick #include "clang/Basic/TokenKinds.h"
22e5dd7070Spatrick #include "llvm/ADT/DenseMapInfo.h"
23e5dd7070Spatrick #include "llvm/ADT/FoldingSet.h"
24e5dd7070Spatrick #include "llvm/ADT/SmallString.h"
25e5dd7070Spatrick #include "llvm/ADT/StringMap.h"
26e5dd7070Spatrick #include "llvm/ADT/StringRef.h"
27e5dd7070Spatrick #include "llvm/Support/Allocator.h"
28e5dd7070Spatrick #include "llvm/Support/ErrorHandling.h"
29e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
30e5dd7070Spatrick #include <cassert>
31e5dd7070Spatrick #include <cstdio>
32e5dd7070Spatrick #include <cstring>
33e5dd7070Spatrick #include <string>
34e5dd7070Spatrick
35e5dd7070Spatrick using namespace clang;
36e5dd7070Spatrick
37ec727ea7Spatrick // A check to make sure the ObjCOrBuiltinID has sufficient room to store the
38ec727ea7Spatrick // largest possible target/aux-target combination. If we exceed this, we likely
39ec727ea7Spatrick // need to just change the ObjCOrBuiltinIDBits value in IdentifierTable.h.
40ec727ea7Spatrick static_assert(2 * LargestBuiltinID < (2 << (ObjCOrBuiltinIDBits - 1)),
41ec727ea7Spatrick "Insufficient ObjCOrBuiltinID Bits");
42ec727ea7Spatrick
43e5dd7070Spatrick //===----------------------------------------------------------------------===//
44e5dd7070Spatrick // IdentifierTable Implementation
45e5dd7070Spatrick //===----------------------------------------------------------------------===//
46e5dd7070Spatrick
47e5dd7070Spatrick IdentifierIterator::~IdentifierIterator() = default;
48e5dd7070Spatrick
49e5dd7070Spatrick IdentifierInfoLookup::~IdentifierInfoLookup() = default;
50e5dd7070Spatrick
51e5dd7070Spatrick namespace {
52e5dd7070Spatrick
53e5dd7070Spatrick /// A simple identifier lookup iterator that represents an
54e5dd7070Spatrick /// empty sequence of identifiers.
55e5dd7070Spatrick class EmptyLookupIterator : public IdentifierIterator
56e5dd7070Spatrick {
57e5dd7070Spatrick public:
Next()58e5dd7070Spatrick StringRef Next() override { return StringRef(); }
59e5dd7070Spatrick };
60e5dd7070Spatrick
61e5dd7070Spatrick } // namespace
62e5dd7070Spatrick
getIdentifiers()63e5dd7070Spatrick IdentifierIterator *IdentifierInfoLookup::getIdentifiers() {
64e5dd7070Spatrick return new EmptyLookupIterator();
65e5dd7070Spatrick }
66e5dd7070Spatrick
IdentifierTable(IdentifierInfoLookup * ExternalLookup)67e5dd7070Spatrick IdentifierTable::IdentifierTable(IdentifierInfoLookup *ExternalLookup)
68e5dd7070Spatrick : HashTable(8192), // Start with space for 8K identifiers.
69e5dd7070Spatrick ExternalLookup(ExternalLookup) {}
70e5dd7070Spatrick
IdentifierTable(const LangOptions & LangOpts,IdentifierInfoLookup * ExternalLookup)71e5dd7070Spatrick IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
72e5dd7070Spatrick IdentifierInfoLookup *ExternalLookup)
73e5dd7070Spatrick : IdentifierTable(ExternalLookup) {
74e5dd7070Spatrick // Populate the identifier table with info about keywords for the current
75e5dd7070Spatrick // language.
76e5dd7070Spatrick AddKeywords(LangOpts);
77e5dd7070Spatrick }
78e5dd7070Spatrick
79e5dd7070Spatrick //===----------------------------------------------------------------------===//
80e5dd7070Spatrick // Language Keyword Implementation
81e5dd7070Spatrick //===----------------------------------------------------------------------===//
82e5dd7070Spatrick
83e5dd7070Spatrick // Constants for TokenKinds.def
84e5dd7070Spatrick namespace {
85e5dd7070Spatrick
86*12c85518Srobert enum TokenKey : unsigned {
87e5dd7070Spatrick KEYC99 = 0x1,
88e5dd7070Spatrick KEYCXX = 0x2,
89e5dd7070Spatrick KEYCXX11 = 0x4,
90e5dd7070Spatrick KEYGNU = 0x8,
91e5dd7070Spatrick KEYMS = 0x10,
92e5dd7070Spatrick BOOLSUPPORT = 0x20,
93e5dd7070Spatrick KEYALTIVEC = 0x40,
94e5dd7070Spatrick KEYNOCXX = 0x80,
95e5dd7070Spatrick KEYBORLAND = 0x100,
96e5dd7070Spatrick KEYOPENCLC = 0x200,
97*12c85518Srobert KEYC2X = 0x400,
98e5dd7070Spatrick KEYNOMS18 = 0x800,
99e5dd7070Spatrick KEYNOOPENCL = 0x1000,
100e5dd7070Spatrick WCHARSUPPORT = 0x2000,
101e5dd7070Spatrick HALFSUPPORT = 0x4000,
102e5dd7070Spatrick CHAR8SUPPORT = 0x8000,
103*12c85518Srobert KEYOBJC = 0x10000,
104*12c85518Srobert KEYZVECTOR = 0x20000,
105*12c85518Srobert KEYCOROUTINES = 0x40000,
106*12c85518Srobert KEYMODULES = 0x80000,
107*12c85518Srobert KEYCXX20 = 0x100000,
108*12c85518Srobert KEYOPENCLCXX = 0x200000,
109*12c85518Srobert KEYMSCOMPAT = 0x400000,
110*12c85518Srobert KEYSYCL = 0x800000,
111*12c85518Srobert KEYCUDA = 0x1000000,
112*12c85518Srobert KEYHLSL = 0x2000000,
113*12c85518Srobert KEYMAX = KEYHLSL, // The maximum key
114ec727ea7Spatrick KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
115*12c85518Srobert KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 &
116*12c85518Srobert ~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude.
117e5dd7070Spatrick };
118e5dd7070Spatrick
119*12c85518Srobert /// How a keyword is treated in the selected standard. This enum is ordered
120*12c85518Srobert /// intentionally so that the value that 'wins' is the most 'permissive'.
121e5dd7070Spatrick enum KeywordStatus {
122*12c85518Srobert KS_Unknown, // Not yet calculated. Used when figuring out the status.
123e5dd7070Spatrick KS_Disabled, // Disabled
124*12c85518Srobert KS_Future, // Is a keyword in future standard
125e5dd7070Spatrick KS_Extension, // Is an extension
126e5dd7070Spatrick KS_Enabled, // Enabled
127e5dd7070Spatrick };
128e5dd7070Spatrick
129e5dd7070Spatrick } // namespace
130e5dd7070Spatrick
131*12c85518Srobert // This works on a single TokenKey flag and checks the LangOpts to get the
132*12c85518Srobert // KeywordStatus based exclusively on this flag, so that it can be merged in
133*12c85518Srobert // getKeywordStatus. Most should be enabled/disabled, but some might imply
134*12c85518Srobert // 'future' versions, or extensions. Returns 'unknown' unless this is KNOWN to
135*12c85518Srobert // be disabled, and the calling function makes it 'disabled' if no other flag
136*12c85518Srobert // changes it. This is necessary for the KEYNOCXX and KEYNOOPENCL flags.
getKeywordStatusHelper(const LangOptions & LangOpts,TokenKey Flag)137*12c85518Srobert static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
138*12c85518Srobert TokenKey Flag) {
139*12c85518Srobert // Flag is a single bit version of TokenKey (that is, not
140*12c85518Srobert // KEYALL/KEYALLCXX/etc), so we can check with == throughout this function.
141*12c85518Srobert assert((Flag & ~(Flag - 1)) == Flag && "Multiple bits set?");
142*12c85518Srobert
143*12c85518Srobert switch (Flag) {
144*12c85518Srobert case KEYC99:
145*12c85518Srobert if (LangOpts.C99)
146*12c85518Srobert return KS_Enabled;
147*12c85518Srobert return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
148*12c85518Srobert case KEYC2X:
149*12c85518Srobert if (LangOpts.C2x)
150*12c85518Srobert return KS_Enabled;
151*12c85518Srobert return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
152*12c85518Srobert case KEYCXX:
153*12c85518Srobert return LangOpts.CPlusPlus ? KS_Enabled : KS_Unknown;
154*12c85518Srobert case KEYCXX11:
155*12c85518Srobert if (LangOpts.CPlusPlus11)
156*12c85518Srobert return KS_Enabled;
157*12c85518Srobert return LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
158*12c85518Srobert case KEYCXX20:
159*12c85518Srobert if (LangOpts.CPlusPlus20)
160*12c85518Srobert return KS_Enabled;
161*12c85518Srobert return LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
162*12c85518Srobert case KEYGNU:
163*12c85518Srobert return LangOpts.GNUKeywords ? KS_Extension : KS_Unknown;
164*12c85518Srobert case KEYMS:
165*12c85518Srobert return LangOpts.MicrosoftExt ? KS_Extension : KS_Unknown;
166*12c85518Srobert case BOOLSUPPORT:
167*12c85518Srobert if (LangOpts.Bool) return KS_Enabled;
168*12c85518Srobert return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
169*12c85518Srobert case KEYALTIVEC:
170*12c85518Srobert return LangOpts.AltiVec ? KS_Enabled : KS_Unknown;
171*12c85518Srobert case KEYBORLAND:
172*12c85518Srobert return LangOpts.Borland ? KS_Extension : KS_Unknown;
173*12c85518Srobert case KEYOPENCLC:
174*12c85518Srobert return LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus ? KS_Enabled
175*12c85518Srobert : KS_Unknown;
176*12c85518Srobert case WCHARSUPPORT:
177*12c85518Srobert return LangOpts.WChar ? KS_Enabled : KS_Unknown;
178*12c85518Srobert case HALFSUPPORT:
179*12c85518Srobert return LangOpts.Half ? KS_Enabled : KS_Unknown;
180*12c85518Srobert case CHAR8SUPPORT:
181*12c85518Srobert if (LangOpts.Char8) return KS_Enabled;
182*12c85518Srobert if (LangOpts.CPlusPlus20) return KS_Unknown;
183*12c85518Srobert if (LangOpts.CPlusPlus) return KS_Future;
184*12c85518Srobert return KS_Unknown;
185*12c85518Srobert case KEYOBJC:
186*12c85518Srobert // We treat bridge casts as objective-C keywords so we can warn on them
187*12c85518Srobert // in non-arc mode.
188*12c85518Srobert return LangOpts.ObjC ? KS_Enabled : KS_Unknown;
189*12c85518Srobert case KEYZVECTOR:
190*12c85518Srobert return LangOpts.ZVector ? KS_Enabled : KS_Unknown;
191*12c85518Srobert case KEYCOROUTINES:
192*12c85518Srobert return LangOpts.Coroutines ? KS_Enabled : KS_Unknown;
193*12c85518Srobert case KEYMODULES:
194*12c85518Srobert return LangOpts.ModulesTS ? KS_Enabled : KS_Unknown;
195*12c85518Srobert case KEYOPENCLCXX:
196*12c85518Srobert return LangOpts.OpenCLCPlusPlus ? KS_Enabled : KS_Unknown;
197*12c85518Srobert case KEYMSCOMPAT:
198*12c85518Srobert return LangOpts.MSVCCompat ? KS_Enabled : KS_Unknown;
199*12c85518Srobert case KEYSYCL:
200*12c85518Srobert return LangOpts.isSYCL() ? KS_Enabled : KS_Unknown;
201*12c85518Srobert case KEYCUDA:
202*12c85518Srobert return LangOpts.CUDA ? KS_Enabled : KS_Unknown;
203*12c85518Srobert case KEYHLSL:
204*12c85518Srobert return LangOpts.HLSL ? KS_Enabled : KS_Unknown;
205*12c85518Srobert case KEYNOCXX:
206*12c85518Srobert // This is enabled in all non-C++ modes, but might be enabled for other
207*12c85518Srobert // reasons as well.
208*12c85518Srobert return LangOpts.CPlusPlus ? KS_Unknown : KS_Enabled;
209*12c85518Srobert case KEYNOOPENCL:
210*12c85518Srobert // The disable behavior for this is handled in getKeywordStatus.
211*12c85518Srobert return KS_Unknown;
212*12c85518Srobert case KEYNOMS18:
213*12c85518Srobert // The disable behavior for this is handled in getKeywordStatus.
214*12c85518Srobert return KS_Unknown;
215*12c85518Srobert default:
216*12c85518Srobert llvm_unreachable("Unknown KeywordStatus flag");
217*12c85518Srobert }
218*12c85518Srobert }
219*12c85518Srobert
220e5dd7070Spatrick /// Translates flags as specified in TokenKinds.def into keyword status
221e5dd7070Spatrick /// in the given language standard.
getKeywordStatus(const LangOptions & LangOpts,unsigned Flags)222e5dd7070Spatrick static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
223e5dd7070Spatrick unsigned Flags) {
224*12c85518Srobert // KEYALL means always enabled, so special case this one.
225e5dd7070Spatrick if (Flags == KEYALL) return KS_Enabled;
226*12c85518Srobert // These are tests that need to 'always win', as they are special in that they
227*12c85518Srobert // disable based on certain conditions.
228*12c85518Srobert if (LangOpts.OpenCL && (Flags & KEYNOOPENCL)) return KS_Disabled;
229*12c85518Srobert if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) &&
230*12c85518Srobert !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015))
231e5dd7070Spatrick return KS_Disabled;
232*12c85518Srobert
233*12c85518Srobert KeywordStatus CurStatus = KS_Unknown;
234*12c85518Srobert
235*12c85518Srobert while (Flags != 0) {
236*12c85518Srobert unsigned CurFlag = Flags & ~(Flags - 1);
237*12c85518Srobert Flags = Flags & ~CurFlag;
238*12c85518Srobert CurStatus = std::max(
239*12c85518Srobert CurStatus,
240*12c85518Srobert getKeywordStatusHelper(LangOpts, static_cast<TokenKey>(CurFlag)));
241*12c85518Srobert }
242*12c85518Srobert
243*12c85518Srobert if (CurStatus == KS_Unknown)
244*12c85518Srobert return KS_Disabled;
245*12c85518Srobert return CurStatus;
246e5dd7070Spatrick }
247e5dd7070Spatrick
248e5dd7070Spatrick /// AddKeyword - This method is used to associate a token ID with specific
249e5dd7070Spatrick /// identifiers because they are language keywords. This causes the lexer to
250e5dd7070Spatrick /// automatically map matching identifiers to specialized token codes.
AddKeyword(StringRef Keyword,tok::TokenKind TokenCode,unsigned Flags,const LangOptions & LangOpts,IdentifierTable & Table)251e5dd7070Spatrick static void AddKeyword(StringRef Keyword,
252e5dd7070Spatrick tok::TokenKind TokenCode, unsigned Flags,
253e5dd7070Spatrick const LangOptions &LangOpts, IdentifierTable &Table) {
254e5dd7070Spatrick KeywordStatus AddResult = getKeywordStatus(LangOpts, Flags);
255e5dd7070Spatrick
256e5dd7070Spatrick // Don't add this keyword if disabled in this language.
257e5dd7070Spatrick if (AddResult == KS_Disabled) return;
258e5dd7070Spatrick
259e5dd7070Spatrick IdentifierInfo &Info =
260e5dd7070Spatrick Table.get(Keyword, AddResult == KS_Future ? tok::identifier : TokenCode);
261e5dd7070Spatrick Info.setIsExtensionToken(AddResult == KS_Extension);
262e5dd7070Spatrick Info.setIsFutureCompatKeyword(AddResult == KS_Future);
263e5dd7070Spatrick }
264e5dd7070Spatrick
265e5dd7070Spatrick /// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
266e5dd7070Spatrick /// representations.
AddCXXOperatorKeyword(StringRef Keyword,tok::TokenKind TokenCode,IdentifierTable & Table)267e5dd7070Spatrick static void AddCXXOperatorKeyword(StringRef Keyword,
268e5dd7070Spatrick tok::TokenKind TokenCode,
269e5dd7070Spatrick IdentifierTable &Table) {
270e5dd7070Spatrick IdentifierInfo &Info = Table.get(Keyword, TokenCode);
271e5dd7070Spatrick Info.setIsCPlusPlusOperatorKeyword();
272e5dd7070Spatrick }
273e5dd7070Spatrick
274e5dd7070Spatrick /// AddObjCKeyword - Register an Objective-C \@keyword like "class" "selector"
275e5dd7070Spatrick /// or "property".
AddObjCKeyword(StringRef Name,tok::ObjCKeywordKind ObjCID,IdentifierTable & Table)276e5dd7070Spatrick static void AddObjCKeyword(StringRef Name,
277e5dd7070Spatrick tok::ObjCKeywordKind ObjCID,
278e5dd7070Spatrick IdentifierTable &Table) {
279e5dd7070Spatrick Table.get(Name).setObjCKeywordID(ObjCID);
280e5dd7070Spatrick }
281e5dd7070Spatrick
282e5dd7070Spatrick /// AddKeywords - Add all keywords to the symbol table.
283e5dd7070Spatrick ///
AddKeywords(const LangOptions & LangOpts)284e5dd7070Spatrick void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
285e5dd7070Spatrick // Add keywords and tokens for the current language.
286e5dd7070Spatrick #define KEYWORD(NAME, FLAGS) \
287e5dd7070Spatrick AddKeyword(StringRef(#NAME), tok::kw_ ## NAME, \
288e5dd7070Spatrick FLAGS, LangOpts, *this);
289e5dd7070Spatrick #define ALIAS(NAME, TOK, FLAGS) \
290e5dd7070Spatrick AddKeyword(StringRef(NAME), tok::kw_ ## TOK, \
291e5dd7070Spatrick FLAGS, LangOpts, *this);
292e5dd7070Spatrick #define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \
293e5dd7070Spatrick if (LangOpts.CXXOperatorNames) \
294e5dd7070Spatrick AddCXXOperatorKeyword(StringRef(#NAME), tok::ALIAS, *this);
295e5dd7070Spatrick #define OBJC_AT_KEYWORD(NAME) \
296e5dd7070Spatrick if (LangOpts.ObjC) \
297e5dd7070Spatrick AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this);
298e5dd7070Spatrick #define TESTING_KEYWORD(NAME, FLAGS)
299e5dd7070Spatrick #include "clang/Basic/TokenKinds.def"
300e5dd7070Spatrick
301e5dd7070Spatrick if (LangOpts.ParseUnknownAnytype)
302e5dd7070Spatrick AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL,
303e5dd7070Spatrick LangOpts, *this);
304e5dd7070Spatrick
305e5dd7070Spatrick if (LangOpts.DeclSpecKeyword)
306e5dd7070Spatrick AddKeyword("__declspec", tok::kw___declspec, KEYALL, LangOpts, *this);
307e5dd7070Spatrick
308a9ac8606Spatrick if (LangOpts.IEEE128)
309a9ac8606Spatrick AddKeyword("__ieee128", tok::kw___float128, KEYALL, LangOpts, *this);
310a9ac8606Spatrick
311e5dd7070Spatrick // Add the 'import' contextual keyword.
312e5dd7070Spatrick get("import").setModulesImport(true);
313e5dd7070Spatrick }
314e5dd7070Spatrick
315e5dd7070Spatrick /// Checks if the specified token kind represents a keyword in the
316e5dd7070Spatrick /// specified language.
317e5dd7070Spatrick /// \returns Status of the keyword in the language.
getTokenKwStatus(const LangOptions & LangOpts,tok::TokenKind K)318e5dd7070Spatrick static KeywordStatus getTokenKwStatus(const LangOptions &LangOpts,
319e5dd7070Spatrick tok::TokenKind K) {
320e5dd7070Spatrick switch (K) {
321e5dd7070Spatrick #define KEYWORD(NAME, FLAGS) \
322e5dd7070Spatrick case tok::kw_##NAME: return getKeywordStatus(LangOpts, FLAGS);
323e5dd7070Spatrick #include "clang/Basic/TokenKinds.def"
324e5dd7070Spatrick default: return KS_Disabled;
325e5dd7070Spatrick }
326e5dd7070Spatrick }
327e5dd7070Spatrick
328e5dd7070Spatrick /// Returns true if the identifier represents a keyword in the
329e5dd7070Spatrick /// specified language.
isKeyword(const LangOptions & LangOpts) const330e5dd7070Spatrick bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) const {
331e5dd7070Spatrick switch (getTokenKwStatus(LangOpts, getTokenID())) {
332e5dd7070Spatrick case KS_Enabled:
333e5dd7070Spatrick case KS_Extension:
334e5dd7070Spatrick return true;
335e5dd7070Spatrick default:
336e5dd7070Spatrick return false;
337e5dd7070Spatrick }
338e5dd7070Spatrick }
339e5dd7070Spatrick
340e5dd7070Spatrick /// Returns true if the identifier represents a C++ keyword in the
341e5dd7070Spatrick /// specified language.
isCPlusPlusKeyword(const LangOptions & LangOpts) const342e5dd7070Spatrick bool IdentifierInfo::isCPlusPlusKeyword(const LangOptions &LangOpts) const {
343e5dd7070Spatrick if (!LangOpts.CPlusPlus || !isKeyword(LangOpts))
344e5dd7070Spatrick return false;
345e5dd7070Spatrick // This is a C++ keyword if this identifier is not a keyword when checked
346e5dd7070Spatrick // using LangOptions without C++ support.
347e5dd7070Spatrick LangOptions LangOptsNoCPP = LangOpts;
348e5dd7070Spatrick LangOptsNoCPP.CPlusPlus = false;
349e5dd7070Spatrick LangOptsNoCPP.CPlusPlus11 = false;
350ec727ea7Spatrick LangOptsNoCPP.CPlusPlus20 = false;
351e5dd7070Spatrick return !isKeyword(LangOptsNoCPP);
352e5dd7070Spatrick }
353e5dd7070Spatrick
354a9ac8606Spatrick ReservedIdentifierStatus
isReserved(const LangOptions & LangOpts) const355a9ac8606Spatrick IdentifierInfo::isReserved(const LangOptions &LangOpts) const {
356a9ac8606Spatrick StringRef Name = getName();
357a9ac8606Spatrick
358a9ac8606Spatrick // '_' is a reserved identifier, but its use is so common (e.g. to store
359a9ac8606Spatrick // ignored values) that we don't warn on it.
360a9ac8606Spatrick if (Name.size() <= 1)
361a9ac8606Spatrick return ReservedIdentifierStatus::NotReserved;
362a9ac8606Spatrick
363a9ac8606Spatrick // [lex.name] p3
364a9ac8606Spatrick if (Name[0] == '_') {
365a9ac8606Spatrick
366a9ac8606Spatrick // Each name that begins with an underscore followed by an uppercase letter
367a9ac8606Spatrick // or another underscore is reserved.
368a9ac8606Spatrick if (Name[1] == '_')
369a9ac8606Spatrick return ReservedIdentifierStatus::StartsWithDoubleUnderscore;
370a9ac8606Spatrick
371a9ac8606Spatrick if ('A' <= Name[1] && Name[1] <= 'Z')
372a9ac8606Spatrick return ReservedIdentifierStatus::
373a9ac8606Spatrick StartsWithUnderscoreFollowedByCapitalLetter;
374a9ac8606Spatrick
375a9ac8606Spatrick // This is a bit misleading: it actually means it's only reserved if we're
376a9ac8606Spatrick // at global scope because it starts with an underscore.
377a9ac8606Spatrick return ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope;
378a9ac8606Spatrick }
379a9ac8606Spatrick
380a9ac8606Spatrick // Each name that contains a double underscore (__) is reserved.
381a9ac8606Spatrick if (LangOpts.CPlusPlus && Name.contains("__"))
382a9ac8606Spatrick return ReservedIdentifierStatus::ContainsDoubleUnderscore;
383a9ac8606Spatrick
384a9ac8606Spatrick return ReservedIdentifierStatus::NotReserved;
385a9ac8606Spatrick }
386a9ac8606Spatrick
deuglifiedName() const387*12c85518Srobert StringRef IdentifierInfo::deuglifiedName() const {
388*12c85518Srobert StringRef Name = getName();
389*12c85518Srobert if (Name.size() >= 2 && Name.front() == '_' &&
390*12c85518Srobert (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')))
391*12c85518Srobert return Name.ltrim('_');
392*12c85518Srobert return Name;
393*12c85518Srobert }
394*12c85518Srobert
getPPKeywordID() const395e5dd7070Spatrick tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
396e5dd7070Spatrick // We use a perfect hash function here involving the length of the keyword,
397e5dd7070Spatrick // the first and third character. For preprocessor ID's there are no
398e5dd7070Spatrick // collisions (if there were, the switch below would complain about duplicate
399e5dd7070Spatrick // case values). Note that this depends on 'if' being null terminated.
400e5dd7070Spatrick
401e5dd7070Spatrick #define HASH(LEN, FIRST, THIRD) \
402e5dd7070Spatrick (LEN << 5) + (((FIRST-'a') + (THIRD-'a')) & 31)
403e5dd7070Spatrick #define CASE(LEN, FIRST, THIRD, NAME) \
404e5dd7070Spatrick case HASH(LEN, FIRST, THIRD): \
405e5dd7070Spatrick return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME
406e5dd7070Spatrick
407e5dd7070Spatrick unsigned Len = getLength();
408e5dd7070Spatrick if (Len < 2) return tok::pp_not_keyword;
409e5dd7070Spatrick const char *Name = getNameStart();
410e5dd7070Spatrick switch (HASH(Len, Name[0], Name[2])) {
411e5dd7070Spatrick default: return tok::pp_not_keyword;
412e5dd7070Spatrick CASE( 2, 'i', '\0', if);
413e5dd7070Spatrick CASE( 4, 'e', 'i', elif);
414e5dd7070Spatrick CASE( 4, 'e', 's', else);
415e5dd7070Spatrick CASE( 4, 'l', 'n', line);
416e5dd7070Spatrick CASE( 4, 's', 'c', sccs);
417e5dd7070Spatrick CASE( 5, 'e', 'd', endif);
418e5dd7070Spatrick CASE( 5, 'e', 'r', error);
419e5dd7070Spatrick CASE( 5, 'i', 'e', ident);
420e5dd7070Spatrick CASE( 5, 'i', 'd', ifdef);
421e5dd7070Spatrick CASE( 5, 'u', 'd', undef);
422e5dd7070Spatrick
423e5dd7070Spatrick CASE( 6, 'a', 's', assert);
424e5dd7070Spatrick CASE( 6, 'd', 'f', define);
425e5dd7070Spatrick CASE( 6, 'i', 'n', ifndef);
426e5dd7070Spatrick CASE( 6, 'i', 'p', import);
427e5dd7070Spatrick CASE( 6, 'p', 'a', pragma);
428e5dd7070Spatrick
429e5dd7070Spatrick CASE( 7, 'd', 'f', defined);
430a9ac8606Spatrick CASE( 7, 'e', 'i', elifdef);
431e5dd7070Spatrick CASE( 7, 'i', 'c', include);
432e5dd7070Spatrick CASE( 7, 'w', 'r', warning);
433e5dd7070Spatrick
434a9ac8606Spatrick CASE( 8, 'e', 'i', elifndef);
435e5dd7070Spatrick CASE( 8, 'u', 'a', unassert);
436e5dd7070Spatrick CASE(12, 'i', 'c', include_next);
437e5dd7070Spatrick
438e5dd7070Spatrick CASE(14, '_', 'p', __public_macro);
439e5dd7070Spatrick
440e5dd7070Spatrick CASE(15, '_', 'p', __private_macro);
441e5dd7070Spatrick
442e5dd7070Spatrick CASE(16, '_', 'i', __include_macros);
443e5dd7070Spatrick #undef CASE
444e5dd7070Spatrick #undef HASH
445e5dd7070Spatrick }
446e5dd7070Spatrick }
447e5dd7070Spatrick
448e5dd7070Spatrick //===----------------------------------------------------------------------===//
449e5dd7070Spatrick // Stats Implementation
450e5dd7070Spatrick //===----------------------------------------------------------------------===//
451e5dd7070Spatrick
452e5dd7070Spatrick /// PrintStats - Print statistics about how well the identifier table is doing
453e5dd7070Spatrick /// at hashing identifiers.
PrintStats() const454e5dd7070Spatrick void IdentifierTable::PrintStats() const {
455e5dd7070Spatrick unsigned NumBuckets = HashTable.getNumBuckets();
456e5dd7070Spatrick unsigned NumIdentifiers = HashTable.getNumItems();
457e5dd7070Spatrick unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers;
458e5dd7070Spatrick unsigned AverageIdentifierSize = 0;
459e5dd7070Spatrick unsigned MaxIdentifierLength = 0;
460e5dd7070Spatrick
461e5dd7070Spatrick // TODO: Figure out maximum times an identifier had to probe for -stats.
462e5dd7070Spatrick for (llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator>::const_iterator
463e5dd7070Spatrick I = HashTable.begin(), E = HashTable.end(); I != E; ++I) {
464e5dd7070Spatrick unsigned IdLen = I->getKeyLength();
465e5dd7070Spatrick AverageIdentifierSize += IdLen;
466e5dd7070Spatrick if (MaxIdentifierLength < IdLen)
467e5dd7070Spatrick MaxIdentifierLength = IdLen;
468e5dd7070Spatrick }
469e5dd7070Spatrick
470e5dd7070Spatrick fprintf(stderr, "\n*** Identifier Table Stats:\n");
471e5dd7070Spatrick fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers);
472e5dd7070Spatrick fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets);
473e5dd7070Spatrick fprintf(stderr, "Hash density (#identifiers per bucket): %f\n",
474e5dd7070Spatrick NumIdentifiers/(double)NumBuckets);
475e5dd7070Spatrick fprintf(stderr, "Ave identifier length: %f\n",
476e5dd7070Spatrick (AverageIdentifierSize/(double)NumIdentifiers));
477e5dd7070Spatrick fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength);
478e5dd7070Spatrick
479e5dd7070Spatrick // Compute statistics about the memory allocated for identifiers.
480e5dd7070Spatrick HashTable.getAllocator().PrintStats();
481e5dd7070Spatrick }
482e5dd7070Spatrick
483e5dd7070Spatrick //===----------------------------------------------------------------------===//
484e5dd7070Spatrick // SelectorTable Implementation
485e5dd7070Spatrick //===----------------------------------------------------------------------===//
486e5dd7070Spatrick
getHashValue(clang::Selector S)487e5dd7070Spatrick unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) {
488e5dd7070Spatrick return DenseMapInfo<void*>::getHashValue(S.getAsOpaquePtr());
489e5dd7070Spatrick }
490e5dd7070Spatrick
491e5dd7070Spatrick namespace clang {
492e5dd7070Spatrick
493e5dd7070Spatrick /// One of these variable length records is kept for each
494e5dd7070Spatrick /// selector containing more than one keyword. We use a folding set
495e5dd7070Spatrick /// to unique aggregate names (keyword selectors in ObjC parlance). Access to
496e5dd7070Spatrick /// this class is provided strictly through Selector.
497e5dd7070Spatrick class alignas(IdentifierInfoAlignment) MultiKeywordSelector
498e5dd7070Spatrick : public detail::DeclarationNameExtra,
499e5dd7070Spatrick public llvm::FoldingSetNode {
MultiKeywordSelector(unsigned nKeys)500e5dd7070Spatrick MultiKeywordSelector(unsigned nKeys) : DeclarationNameExtra(nKeys) {}
501e5dd7070Spatrick
502e5dd7070Spatrick public:
503e5dd7070Spatrick // Constructor for keyword selectors.
MultiKeywordSelector(unsigned nKeys,IdentifierInfo ** IIV)504e5dd7070Spatrick MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV)
505e5dd7070Spatrick : DeclarationNameExtra(nKeys) {
506e5dd7070Spatrick assert((nKeys > 1) && "not a multi-keyword selector");
507e5dd7070Spatrick
508e5dd7070Spatrick // Fill in the trailing keyword array.
509e5dd7070Spatrick IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(this + 1);
510e5dd7070Spatrick for (unsigned i = 0; i != nKeys; ++i)
511e5dd7070Spatrick KeyInfo[i] = IIV[i];
512e5dd7070Spatrick }
513e5dd7070Spatrick
514e5dd7070Spatrick // getName - Derive the full selector name and return it.
515e5dd7070Spatrick std::string getName() const;
516e5dd7070Spatrick
517e5dd7070Spatrick using DeclarationNameExtra::getNumArgs;
518e5dd7070Spatrick
519e5dd7070Spatrick using keyword_iterator = IdentifierInfo *const *;
520e5dd7070Spatrick
keyword_begin() const521e5dd7070Spatrick keyword_iterator keyword_begin() const {
522e5dd7070Spatrick return reinterpret_cast<keyword_iterator>(this + 1);
523e5dd7070Spatrick }
524e5dd7070Spatrick
keyword_end() const525e5dd7070Spatrick keyword_iterator keyword_end() const {
526e5dd7070Spatrick return keyword_begin() + getNumArgs();
527e5dd7070Spatrick }
528e5dd7070Spatrick
getIdentifierInfoForSlot(unsigned i) const529e5dd7070Spatrick IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const {
530e5dd7070Spatrick assert(i < getNumArgs() && "getIdentifierInfoForSlot(): illegal index");
531e5dd7070Spatrick return keyword_begin()[i];
532e5dd7070Spatrick }
533e5dd7070Spatrick
Profile(llvm::FoldingSetNodeID & ID,keyword_iterator ArgTys,unsigned NumArgs)534e5dd7070Spatrick static void Profile(llvm::FoldingSetNodeID &ID, keyword_iterator ArgTys,
535e5dd7070Spatrick unsigned NumArgs) {
536e5dd7070Spatrick ID.AddInteger(NumArgs);
537e5dd7070Spatrick for (unsigned i = 0; i != NumArgs; ++i)
538e5dd7070Spatrick ID.AddPointer(ArgTys[i]);
539e5dd7070Spatrick }
540e5dd7070Spatrick
Profile(llvm::FoldingSetNodeID & ID)541e5dd7070Spatrick void Profile(llvm::FoldingSetNodeID &ID) {
542e5dd7070Spatrick Profile(ID, keyword_begin(), getNumArgs());
543e5dd7070Spatrick }
544e5dd7070Spatrick };
545e5dd7070Spatrick
546e5dd7070Spatrick } // namespace clang.
547e5dd7070Spatrick
isKeywordSelector(ArrayRef<StringRef> Names) const548e5dd7070Spatrick bool Selector::isKeywordSelector(ArrayRef<StringRef> Names) const {
549e5dd7070Spatrick assert(!Names.empty() && "must have >= 1 selector slots");
550e5dd7070Spatrick if (getNumArgs() != Names.size())
551e5dd7070Spatrick return false;
552e5dd7070Spatrick for (unsigned I = 0, E = Names.size(); I != E; ++I) {
553e5dd7070Spatrick if (getNameForSlot(I) != Names[I])
554e5dd7070Spatrick return false;
555e5dd7070Spatrick }
556e5dd7070Spatrick return true;
557e5dd7070Spatrick }
558e5dd7070Spatrick
isUnarySelector(StringRef Name) const559e5dd7070Spatrick bool Selector::isUnarySelector(StringRef Name) const {
560e5dd7070Spatrick return isUnarySelector() && getNameForSlot(0) == Name;
561e5dd7070Spatrick }
562e5dd7070Spatrick
getNumArgs() const563e5dd7070Spatrick unsigned Selector::getNumArgs() const {
564e5dd7070Spatrick unsigned IIF = getIdentifierInfoFlag();
565e5dd7070Spatrick if (IIF <= ZeroArg)
566e5dd7070Spatrick return 0;
567e5dd7070Spatrick if (IIF == OneArg)
568e5dd7070Spatrick return 1;
569e5dd7070Spatrick // We point to a MultiKeywordSelector.
570e5dd7070Spatrick MultiKeywordSelector *SI = getMultiKeywordSelector();
571e5dd7070Spatrick return SI->getNumArgs();
572e5dd7070Spatrick }
573e5dd7070Spatrick
getIdentifierInfoForSlot(unsigned argIndex) const574e5dd7070Spatrick IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const {
575e5dd7070Spatrick if (getIdentifierInfoFlag() < MultiArg) {
576e5dd7070Spatrick assert(argIndex == 0 && "illegal keyword index");
577e5dd7070Spatrick return getAsIdentifierInfo();
578e5dd7070Spatrick }
579e5dd7070Spatrick
580e5dd7070Spatrick // We point to a MultiKeywordSelector.
581e5dd7070Spatrick MultiKeywordSelector *SI = getMultiKeywordSelector();
582e5dd7070Spatrick return SI->getIdentifierInfoForSlot(argIndex);
583e5dd7070Spatrick }
584e5dd7070Spatrick
getNameForSlot(unsigned int argIndex) const585e5dd7070Spatrick StringRef Selector::getNameForSlot(unsigned int argIndex) const {
586e5dd7070Spatrick IdentifierInfo *II = getIdentifierInfoForSlot(argIndex);
587e5dd7070Spatrick return II ? II->getName() : StringRef();
588e5dd7070Spatrick }
589e5dd7070Spatrick
getName() const590e5dd7070Spatrick std::string MultiKeywordSelector::getName() const {
591e5dd7070Spatrick SmallString<256> Str;
592e5dd7070Spatrick llvm::raw_svector_ostream OS(Str);
593e5dd7070Spatrick for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) {
594e5dd7070Spatrick if (*I)
595e5dd7070Spatrick OS << (*I)->getName();
596e5dd7070Spatrick OS << ':';
597e5dd7070Spatrick }
598e5dd7070Spatrick
599ec727ea7Spatrick return std::string(OS.str());
600e5dd7070Spatrick }
601e5dd7070Spatrick
getAsString() const602e5dd7070Spatrick std::string Selector::getAsString() const {
603e5dd7070Spatrick if (InfoPtr == 0)
604e5dd7070Spatrick return "<null selector>";
605e5dd7070Spatrick
606e5dd7070Spatrick if (getIdentifierInfoFlag() < MultiArg) {
607e5dd7070Spatrick IdentifierInfo *II = getAsIdentifierInfo();
608e5dd7070Spatrick
609e5dd7070Spatrick if (getNumArgs() == 0) {
610e5dd7070Spatrick assert(II && "If the number of arguments is 0 then II is guaranteed to "
611e5dd7070Spatrick "not be null.");
612ec727ea7Spatrick return std::string(II->getName());
613e5dd7070Spatrick }
614e5dd7070Spatrick
615e5dd7070Spatrick if (!II)
616e5dd7070Spatrick return ":";
617e5dd7070Spatrick
618e5dd7070Spatrick return II->getName().str() + ":";
619e5dd7070Spatrick }
620e5dd7070Spatrick
621e5dd7070Spatrick // We have a multiple keyword selector.
622e5dd7070Spatrick return getMultiKeywordSelector()->getName();
623e5dd7070Spatrick }
624e5dd7070Spatrick
print(llvm::raw_ostream & OS) const625e5dd7070Spatrick void Selector::print(llvm::raw_ostream &OS) const {
626e5dd7070Spatrick OS << getAsString();
627e5dd7070Spatrick }
628e5dd7070Spatrick
dump() const629e5dd7070Spatrick LLVM_DUMP_METHOD void Selector::dump() const { print(llvm::errs()); }
630e5dd7070Spatrick
631e5dd7070Spatrick /// Interpreting the given string using the normal CamelCase
632e5dd7070Spatrick /// conventions, determine whether the given string starts with the
633e5dd7070Spatrick /// given "word", which is assumed to end in a lowercase letter.
startsWithWord(StringRef name,StringRef word)634e5dd7070Spatrick static bool startsWithWord(StringRef name, StringRef word) {
635e5dd7070Spatrick if (name.size() < word.size()) return false;
636e5dd7070Spatrick return ((name.size() == word.size() || !isLowercase(name[word.size()])) &&
637e5dd7070Spatrick name.startswith(word));
638e5dd7070Spatrick }
639e5dd7070Spatrick
getMethodFamilyImpl(Selector sel)640e5dd7070Spatrick ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
641e5dd7070Spatrick IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
642e5dd7070Spatrick if (!first) return OMF_None;
643e5dd7070Spatrick
644e5dd7070Spatrick StringRef name = first->getName();
645e5dd7070Spatrick if (sel.isUnarySelector()) {
646e5dd7070Spatrick if (name == "autorelease") return OMF_autorelease;
647e5dd7070Spatrick if (name == "dealloc") return OMF_dealloc;
648e5dd7070Spatrick if (name == "finalize") return OMF_finalize;
649e5dd7070Spatrick if (name == "release") return OMF_release;
650e5dd7070Spatrick if (name == "retain") return OMF_retain;
651e5dd7070Spatrick if (name == "retainCount") return OMF_retainCount;
652e5dd7070Spatrick if (name == "self") return OMF_self;
653e5dd7070Spatrick if (name == "initialize") return OMF_initialize;
654e5dd7070Spatrick }
655e5dd7070Spatrick
656e5dd7070Spatrick if (name == "performSelector" || name == "performSelectorInBackground" ||
657e5dd7070Spatrick name == "performSelectorOnMainThread")
658e5dd7070Spatrick return OMF_performSelector;
659e5dd7070Spatrick
660e5dd7070Spatrick // The other method families may begin with a prefix of underscores.
661e5dd7070Spatrick while (!name.empty() && name.front() == '_')
662e5dd7070Spatrick name = name.substr(1);
663e5dd7070Spatrick
664e5dd7070Spatrick if (name.empty()) return OMF_None;
665e5dd7070Spatrick switch (name.front()) {
666e5dd7070Spatrick case 'a':
667e5dd7070Spatrick if (startsWithWord(name, "alloc")) return OMF_alloc;
668e5dd7070Spatrick break;
669e5dd7070Spatrick case 'c':
670e5dd7070Spatrick if (startsWithWord(name, "copy")) return OMF_copy;
671e5dd7070Spatrick break;
672e5dd7070Spatrick case 'i':
673e5dd7070Spatrick if (startsWithWord(name, "init")) return OMF_init;
674e5dd7070Spatrick break;
675e5dd7070Spatrick case 'm':
676e5dd7070Spatrick if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy;
677e5dd7070Spatrick break;
678e5dd7070Spatrick case 'n':
679e5dd7070Spatrick if (startsWithWord(name, "new")) return OMF_new;
680e5dd7070Spatrick break;
681e5dd7070Spatrick default:
682e5dd7070Spatrick break;
683e5dd7070Spatrick }
684e5dd7070Spatrick
685e5dd7070Spatrick return OMF_None;
686e5dd7070Spatrick }
687e5dd7070Spatrick
getInstTypeMethodFamily(Selector sel)688e5dd7070Spatrick ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) {
689e5dd7070Spatrick IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
690e5dd7070Spatrick if (!first) return OIT_None;
691e5dd7070Spatrick
692e5dd7070Spatrick StringRef name = first->getName();
693e5dd7070Spatrick
694e5dd7070Spatrick if (name.empty()) return OIT_None;
695e5dd7070Spatrick switch (name.front()) {
696e5dd7070Spatrick case 'a':
697e5dd7070Spatrick if (startsWithWord(name, "array")) return OIT_Array;
698e5dd7070Spatrick break;
699e5dd7070Spatrick case 'd':
700e5dd7070Spatrick if (startsWithWord(name, "default")) return OIT_ReturnsSelf;
701e5dd7070Spatrick if (startsWithWord(name, "dictionary")) return OIT_Dictionary;
702e5dd7070Spatrick break;
703e5dd7070Spatrick case 's':
704e5dd7070Spatrick if (startsWithWord(name, "shared")) return OIT_ReturnsSelf;
705e5dd7070Spatrick if (startsWithWord(name, "standard")) return OIT_Singleton;
706e5dd7070Spatrick break;
707e5dd7070Spatrick case 'i':
708e5dd7070Spatrick if (startsWithWord(name, "init")) return OIT_Init;
709e5dd7070Spatrick break;
710e5dd7070Spatrick default:
711e5dd7070Spatrick break;
712e5dd7070Spatrick }
713e5dd7070Spatrick return OIT_None;
714e5dd7070Spatrick }
715e5dd7070Spatrick
getStringFormatFamilyImpl(Selector sel)716e5dd7070Spatrick ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) {
717e5dd7070Spatrick IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
718e5dd7070Spatrick if (!first) return SFF_None;
719e5dd7070Spatrick
720e5dd7070Spatrick StringRef name = first->getName();
721e5dd7070Spatrick
722e5dd7070Spatrick switch (name.front()) {
723e5dd7070Spatrick case 'a':
724e5dd7070Spatrick if (name == "appendFormat") return SFF_NSString;
725e5dd7070Spatrick break;
726e5dd7070Spatrick
727e5dd7070Spatrick case 'i':
728e5dd7070Spatrick if (name == "initWithFormat") return SFF_NSString;
729e5dd7070Spatrick break;
730e5dd7070Spatrick
731e5dd7070Spatrick case 'l':
732e5dd7070Spatrick if (name == "localizedStringWithFormat") return SFF_NSString;
733e5dd7070Spatrick break;
734e5dd7070Spatrick
735e5dd7070Spatrick case 's':
736e5dd7070Spatrick if (name == "stringByAppendingFormat" ||
737e5dd7070Spatrick name == "stringWithFormat") return SFF_NSString;
738e5dd7070Spatrick break;
739e5dd7070Spatrick }
740e5dd7070Spatrick return SFF_None;
741e5dd7070Spatrick }
742e5dd7070Spatrick
743e5dd7070Spatrick namespace {
744e5dd7070Spatrick
745e5dd7070Spatrick struct SelectorTableImpl {
746e5dd7070Spatrick llvm::FoldingSet<MultiKeywordSelector> Table;
747e5dd7070Spatrick llvm::BumpPtrAllocator Allocator;
748e5dd7070Spatrick };
749e5dd7070Spatrick
750e5dd7070Spatrick } // namespace
751e5dd7070Spatrick
getSelectorTableImpl(void * P)752e5dd7070Spatrick static SelectorTableImpl &getSelectorTableImpl(void *P) {
753e5dd7070Spatrick return *static_cast<SelectorTableImpl*>(P);
754e5dd7070Spatrick }
755e5dd7070Spatrick
756e5dd7070Spatrick SmallString<64>
constructSetterName(StringRef Name)757e5dd7070Spatrick SelectorTable::constructSetterName(StringRef Name) {
758e5dd7070Spatrick SmallString<64> SetterName("set");
759e5dd7070Spatrick SetterName += Name;
760e5dd7070Spatrick SetterName[3] = toUppercase(SetterName[3]);
761e5dd7070Spatrick return SetterName;
762e5dd7070Spatrick }
763e5dd7070Spatrick
764e5dd7070Spatrick Selector
constructSetterSelector(IdentifierTable & Idents,SelectorTable & SelTable,const IdentifierInfo * Name)765e5dd7070Spatrick SelectorTable::constructSetterSelector(IdentifierTable &Idents,
766e5dd7070Spatrick SelectorTable &SelTable,
767e5dd7070Spatrick const IdentifierInfo *Name) {
768e5dd7070Spatrick IdentifierInfo *SetterName =
769e5dd7070Spatrick &Idents.get(constructSetterName(Name->getName()));
770e5dd7070Spatrick return SelTable.getUnarySelector(SetterName);
771e5dd7070Spatrick }
772e5dd7070Spatrick
getPropertyNameFromSetterSelector(Selector Sel)773e5dd7070Spatrick std::string SelectorTable::getPropertyNameFromSetterSelector(Selector Sel) {
774e5dd7070Spatrick StringRef Name = Sel.getNameForSlot(0);
775e5dd7070Spatrick assert(Name.startswith("set") && "invalid setter name");
776e5dd7070Spatrick return (Twine(toLowercase(Name[3])) + Name.drop_front(4)).str();
777e5dd7070Spatrick }
778e5dd7070Spatrick
getTotalMemory() const779e5dd7070Spatrick size_t SelectorTable::getTotalMemory() const {
780e5dd7070Spatrick SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
781e5dd7070Spatrick return SelTabImpl.Allocator.getTotalMemory();
782e5dd7070Spatrick }
783e5dd7070Spatrick
getSelector(unsigned nKeys,IdentifierInfo ** IIV)784e5dd7070Spatrick Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) {
785e5dd7070Spatrick if (nKeys < 2)
786e5dd7070Spatrick return Selector(IIV[0], nKeys);
787e5dd7070Spatrick
788e5dd7070Spatrick SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
789e5dd7070Spatrick
790e5dd7070Spatrick // Unique selector, to guarantee there is one per name.
791e5dd7070Spatrick llvm::FoldingSetNodeID ID;
792e5dd7070Spatrick MultiKeywordSelector::Profile(ID, IIV, nKeys);
793e5dd7070Spatrick
794e5dd7070Spatrick void *InsertPos = nullptr;
795e5dd7070Spatrick if (MultiKeywordSelector *SI =
796e5dd7070Spatrick SelTabImpl.Table.FindNodeOrInsertPos(ID, InsertPos))
797e5dd7070Spatrick return Selector(SI);
798e5dd7070Spatrick
799e5dd7070Spatrick // MultiKeywordSelector objects are not allocated with new because they have a
800e5dd7070Spatrick // variable size array (for parameter types) at the end of them.
801e5dd7070Spatrick unsigned Size = sizeof(MultiKeywordSelector) + nKeys*sizeof(IdentifierInfo *);
802e5dd7070Spatrick MultiKeywordSelector *SI =
803e5dd7070Spatrick (MultiKeywordSelector *)SelTabImpl.Allocator.Allocate(
804e5dd7070Spatrick Size, alignof(MultiKeywordSelector));
805e5dd7070Spatrick new (SI) MultiKeywordSelector(nKeys, IIV);
806e5dd7070Spatrick SelTabImpl.Table.InsertNode(SI, InsertPos);
807e5dd7070Spatrick return Selector(SI);
808e5dd7070Spatrick }
809e5dd7070Spatrick
SelectorTable()810e5dd7070Spatrick SelectorTable::SelectorTable() {
811e5dd7070Spatrick Impl = new SelectorTableImpl();
812e5dd7070Spatrick }
813e5dd7070Spatrick
~SelectorTable()814e5dd7070Spatrick SelectorTable::~SelectorTable() {
815e5dd7070Spatrick delete &getSelectorTableImpl(Impl);
816e5dd7070Spatrick }
817e5dd7070Spatrick
getOperatorSpelling(OverloadedOperatorKind Operator)818e5dd7070Spatrick const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) {
819e5dd7070Spatrick switch (Operator) {
820e5dd7070Spatrick case OO_None:
821e5dd7070Spatrick case NUM_OVERLOADED_OPERATORS:
822e5dd7070Spatrick return nullptr;
823e5dd7070Spatrick
824e5dd7070Spatrick #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
825e5dd7070Spatrick case OO_##Name: return Spelling;
826e5dd7070Spatrick #include "clang/Basic/OperatorKinds.def"
827e5dd7070Spatrick }
828e5dd7070Spatrick
829e5dd7070Spatrick llvm_unreachable("Invalid OverloadedOperatorKind!");
830e5dd7070Spatrick }
831e5dd7070Spatrick
getNullabilitySpelling(NullabilityKind kind,bool isContextSensitive)832e5dd7070Spatrick StringRef clang::getNullabilitySpelling(NullabilityKind kind,
833e5dd7070Spatrick bool isContextSensitive) {
834e5dd7070Spatrick switch (kind) {
835e5dd7070Spatrick case NullabilityKind::NonNull:
836e5dd7070Spatrick return isContextSensitive ? "nonnull" : "_Nonnull";
837e5dd7070Spatrick
838e5dd7070Spatrick case NullabilityKind::Nullable:
839e5dd7070Spatrick return isContextSensitive ? "nullable" : "_Nullable";
840e5dd7070Spatrick
841a9ac8606Spatrick case NullabilityKind::NullableResult:
842a9ac8606Spatrick assert(!isContextSensitive &&
843a9ac8606Spatrick "_Nullable_result isn't supported as context-sensitive keyword");
844a9ac8606Spatrick return "_Nullable_result";
845a9ac8606Spatrick
846e5dd7070Spatrick case NullabilityKind::Unspecified:
847e5dd7070Spatrick return isContextSensitive ? "null_unspecified" : "_Null_unspecified";
848e5dd7070Spatrick }
849e5dd7070Spatrick llvm_unreachable("Unknown nullability kind.");
850e5dd7070Spatrick }
851*12c85518Srobert
852*12c85518Srobert diag::kind
getFutureCompatDiagKind(const IdentifierInfo & II,const LangOptions & LangOpts)853*12c85518Srobert IdentifierTable::getFutureCompatDiagKind(const IdentifierInfo &II,
854*12c85518Srobert const LangOptions &LangOpts) {
855*12c85518Srobert assert(II.isFutureCompatKeyword() && "diagnostic should not be needed");
856*12c85518Srobert
857*12c85518Srobert unsigned Flags = llvm::StringSwitch<unsigned>(II.getName())
858*12c85518Srobert #define KEYWORD(NAME, FLAGS) .Case(#NAME, FLAGS)
859*12c85518Srobert #include "clang/Basic/TokenKinds.def"
860*12c85518Srobert #undef KEYWORD
861*12c85518Srobert ;
862*12c85518Srobert
863*12c85518Srobert if (LangOpts.CPlusPlus) {
864*12c85518Srobert if ((Flags & KEYCXX11) == KEYCXX11)
865*12c85518Srobert return diag::warn_cxx11_keyword;
866*12c85518Srobert
867*12c85518Srobert // char8_t is not modeled as a CXX20_KEYWORD because it's not
868*12c85518Srobert // unconditionally enabled in C++20 mode. (It can be disabled
869*12c85518Srobert // by -fno-char8_t.)
870*12c85518Srobert if (((Flags & KEYCXX20) == KEYCXX20) ||
871*12c85518Srobert ((Flags & CHAR8SUPPORT) == CHAR8SUPPORT))
872*12c85518Srobert return diag::warn_cxx20_keyword;
873*12c85518Srobert } else {
874*12c85518Srobert if ((Flags & KEYC99) == KEYC99)
875*12c85518Srobert return diag::warn_c99_keyword;
876*12c85518Srobert if ((Flags & KEYC2X) == KEYC2X)
877*12c85518Srobert return diag::warn_c2x_keyword;
878*12c85518Srobert }
879*12c85518Srobert
880*12c85518Srobert llvm_unreachable(
881*12c85518Srobert "Keyword not known to come from a newer Standard or proposed Standard");
882*12c85518Srobert }
883