clang 22.0.0git
IdentifierTable.cpp
Go to the documentation of this file.
1//===- IdentifierTable.cpp - Hash table for identifier lookup -------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the IdentifierInfo, IdentifierVisitor, and
10// IdentifierTable interfaces.
11//
12//===----------------------------------------------------------------------===//
13
22#include "llvm/ADT/DenseMapInfo.h"
23#include "llvm/ADT/FoldingSet.h"
24#include "llvm/ADT/StringMap.h"
25#include "llvm/ADT/StringRef.h"
26#include "llvm/Support/Allocator.h"
27#include "llvm/Support/raw_ostream.h"
28#include <cassert>
29#include <cstdio>
30#include <cstring>
31#include <string>
32
33using namespace clang;
34
35// A check to make sure the ObjCOrBuiltinID has sufficient room to store the
36// largest possible target/aux-target combination. If we exceed this, we likely
37// need to just change the ObjCOrBuiltinIDBits value in IdentifierTable.h.
38static_assert(2 * LargestBuiltinID < (2 << (InterestingIdentifierBits - 1)),
39 "Insufficient ObjCOrBuiltinID Bits");
40
41//===----------------------------------------------------------------------===//
42// IdentifierTable Implementation
43//===----------------------------------------------------------------------===//
44
46
48
49namespace {
50
51/// A simple identifier lookup iterator that represents an
52/// empty sequence of identifiers.
53class EmptyLookupIterator : public IdentifierIterator {
54public:
55 StringRef Next() override { return StringRef(); }
56};
57
58} // namespace
59
61 return new EmptyLookupIterator();
62}
63
65 : HashTable(8192), // Start with space for 8K identifiers.
66 ExternalLookup(ExternalLookup) {}
67
69 IdentifierInfoLookup *ExternalLookup)
70 : IdentifierTable(ExternalLookup) {
71 // Populate the identifier table with info about keywords for the current
72 // language.
73 AddKeywords(LangOpts);
74}
75
76//===----------------------------------------------------------------------===//
77// Language Keyword Implementation
78//===----------------------------------------------------------------------===//
79
80// This works on a single TokenKey flag and checks the LangOpts to get the
81// KeywordStatus based exclusively on this flag, so that it can be merged in
82// getKeywordStatus. Most should be enabled/disabled, but some might imply
83// 'future' versions, or extensions. Returns 'unknown' unless this is KNOWN to
84// be disabled, and the calling function makes it 'disabled' if no other flag
85// changes it. This is necessary for the KEYNOCXX and KEYNOOPENCL flags.
87 TokenKey Flag) {
88 // Flag is a single bit version of TokenKey (that is, not
89 // KEYALL/KEYALLCXX/etc), so we can check with == throughout this function.
90 assert((Flag & ~(Flag - 1)) == Flag && "Multiple bits set?");
91
92 switch (Flag) {
93 case KEYC99:
94 if (LangOpts.C99)
95 return KS_Enabled;
96 return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
97 case KEYC23:
98 if (LangOpts.C23)
99 return KS_Enabled;
100 return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
101 case KEYCXX:
102 return LangOpts.CPlusPlus ? KS_Enabled : KS_Unknown;
103 case KEYCXX11:
104 if (LangOpts.CPlusPlus11)
105 return KS_Enabled;
106 return LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
107 case KEYCXX20:
108 if (LangOpts.CPlusPlus20)
109 return KS_Enabled;
110 return LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
111 case KEYGNU:
112 return LangOpts.GNUKeywords ? KS_Extension : KS_Unknown;
113 case KEYMS:
114 return LangOpts.MicrosoftExt ? KS_Extension : KS_Unknown;
115 case BOOLSUPPORT:
116 if (LangOpts.Bool) return KS_Enabled;
117 return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
118 case KEYALTIVEC:
119 return LangOpts.AltiVec ? KS_Enabled : KS_Unknown;
120 case KEYBORLAND:
121 return LangOpts.Borland ? KS_Extension : KS_Unknown;
122 case KEYOPENCLC:
123 return LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus ? KS_Enabled
124 : KS_Unknown;
125 case WCHARSUPPORT:
126 return LangOpts.WChar ? KS_Enabled : KS_Unknown;
127 case HALFSUPPORT:
128 return LangOpts.Half ? KS_Enabled : KS_Unknown;
129 case CHAR8SUPPORT:
130 if (LangOpts.Char8) return KS_Enabled;
131 if (LangOpts.CPlusPlus20) return KS_Unknown;
132 if (LangOpts.CPlusPlus) return KS_Future;
133 return KS_Unknown;
134 case KEYOBJC:
135 // We treat bridge casts as objective-C keywords so we can warn on them
136 // in non-arc mode.
137 return LangOpts.ObjC ? KS_Enabled : KS_Unknown;
138 case KEYZVECTOR:
139 return LangOpts.ZVector ? KS_Enabled : KS_Unknown;
140 case KEYCOROUTINES:
141 return LangOpts.Coroutines ? KS_Enabled : KS_Unknown;
142 case KEYMODULES:
143 return KS_Unknown;
144 case KEYOPENCLCXX:
145 return LangOpts.OpenCLCPlusPlus ? KS_Enabled : KS_Unknown;
146 case KEYMSCOMPAT:
147 return LangOpts.MSVCCompat ? KS_Enabled : KS_Unknown;
148 case KEYSYCL:
149 return LangOpts.isSYCL() ? KS_Enabled : KS_Unknown;
150 case KEYCUDA:
151 return LangOpts.CUDA ? KS_Enabled : KS_Unknown;
152 case KEYZOS:
153 return LangOpts.ZOSExt ? KS_Enabled : KS_Unknown;
154 case KEYHLSL:
155 return LangOpts.HLSL ? KS_Enabled : KS_Unknown;
156 case KEYNOCXX:
157 // This is enabled in all non-C++ modes, but might be enabled for other
158 // reasons as well.
159 return LangOpts.CPlusPlus ? KS_Unknown : KS_Enabled;
160 case KEYNOOPENCL:
161 case KEYNOMS18:
162 case KEYNOZOS:
163 // The disable behavior for this is handled in getKeywordStatus.
164 return KS_Unknown;
165 case KEYFIXEDPOINT:
166 return LangOpts.FixedPoint ? KS_Enabled : KS_Disabled;
167 default:
168 llvm_unreachable("Unknown KeywordStatus flag");
169 }
170}
171
173 unsigned Flags) {
174 // KEYALL means always enabled, so special case this one.
175 if (Flags == KEYALL) return KS_Enabled;
176 // These are tests that need to 'always win', as they are special in that they
177 // disable based on certain conditions.
178 if (LangOpts.OpenCL && (Flags & KEYNOOPENCL)) return KS_Disabled;
179 if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) &&
181 return KS_Disabled;
182 if (LangOpts.ZOSExt && (Flags & KEYNOZOS))
183 return KS_Disabled;
184 KeywordStatus CurStatus = KS_Unknown;
185
186 while (Flags != 0) {
187 unsigned CurFlag = Flags & ~(Flags - 1);
188 Flags = Flags & ~CurFlag;
189 CurStatus = std::max(
190 CurStatus,
191 getKeywordStatusHelper(LangOpts, static_cast<TokenKey>(CurFlag)));
192 }
193
194 if (CurStatus == KS_Unknown)
195 return KS_Disabled;
196 return CurStatus;
197}
198
199static bool IsKeywordInCpp(unsigned Flags) {
200 return (Flags & (KEYCXX | KEYCXX11 | KEYCXX20 | BOOLSUPPORT | WCHARSUPPORT |
201 CHAR8SUPPORT)) != 0;
202}
203
205 StringRef Name) {
206 IdentifierInfo &II = Table.get(Name, tok::identifier);
209}
210
211/// AddKeyword - This method is used to associate a token ID with specific
212/// identifiers because they are language keywords. This causes the lexer to
213/// automatically map matching identifiers to specialized token codes.
214static void AddKeyword(StringRef Keyword,
215 tok::TokenKind TokenCode, unsigned Flags,
216 const LangOptions &LangOpts, IdentifierTable &Table) {
217 KeywordStatus AddResult = getKeywordStatus(LangOpts, Flags);
218
219 // Don't add this keyword if disabled in this language and isn't otherwise
220 // special.
221 if (AddResult == KS_Disabled) {
222 // We do not consider any identifiers to be C++ keywords when in
223 // Objective-C because @ effectively introduces a custom grammar where C++
224 // keywords can be used (and similar for selectors). We could enable this
225 // for Objective-C, but it would require more logic to ensure we do not
226 // issue compatibility diagnostics in these cases.
227 if (!LangOpts.ObjC && IsKeywordInCpp(Flags))
229 return;
230 }
231
232 IdentifierInfo &Info =
233 Table.get(Keyword, AddResult == KS_Future ? tok::identifier : TokenCode);
234 Info.setIsExtensionToken(AddResult == KS_Extension);
235 Info.setIsFutureCompatKeyword(AddResult == KS_Future);
236}
237
238/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
239/// representations.
240static void AddCXXOperatorKeyword(StringRef Keyword,
241 tok::TokenKind TokenCode,
242 IdentifierTable &Table) {
243 IdentifierInfo &Info = Table.get(Keyword, TokenCode);
245}
246
247/// AddObjCKeyword - Register an Objective-C \@keyword like "class" "selector"
248/// or "property".
249static void AddObjCKeyword(StringRef Name,
251 IdentifierTable &Table) {
252 Table.get(Name).setObjCKeywordID(ObjCID);
253}
254
255static void AddNotableIdentifier(StringRef Name,
257 IdentifierTable &Table) {
258 // Don't add 'not_notable' identifier.
259 if (BTID != tok::not_notable) {
260 IdentifierInfo &Info = Table.get(Name, tok::identifier);
261 Info.setNotableIdentifierID(BTID);
262 }
263}
264
265/// AddKeywords - Add all keywords to the symbol table.
266///
268 // Add keywords and tokens for the current language.
269#define KEYWORD(NAME, FLAGS) \
270 AddKeyword(StringRef(#NAME), tok::kw_ ## NAME, \
271 FLAGS, LangOpts, *this);
272#define ALIAS(NAME, TOK, FLAGS) \
273 AddKeyword(StringRef(NAME), tok::kw_ ## TOK, \
274 FLAGS, LangOpts, *this);
275#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \
276 if (LangOpts.CXXOperatorNames) \
277 AddCXXOperatorKeyword(StringRef(#NAME), tok::ALIAS, *this); \
278 else \
279 MarkIdentifierAsKeywordInCpp(*this, StringRef(#NAME));
280#define OBJC_AT_KEYWORD(NAME) \
281 if (LangOpts.ObjC) \
282 AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this);
283#define NOTABLE_IDENTIFIER(NAME) \
284 AddNotableIdentifier(StringRef(#NAME), tok::NAME, *this);
285
286#define TESTING_KEYWORD(NAME, FLAGS)
287#include "clang/Basic/TokenKinds.def"
288
289 if (LangOpts.ParseUnknownAnytype)
290 AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL,
291 LangOpts, *this);
292
293 if (LangOpts.DeclSpecKeyword)
294 AddKeyword("__declspec", tok::kw___declspec, KEYALL, LangOpts, *this);
295
296 if (LangOpts.IEEE128)
297 AddKeyword("__ieee128", tok::kw___float128, KEYALL, LangOpts, *this);
298
299 // Add the 'import' contextual keyword.
300 get("import").setModulesImport(true);
301}
302
303/// Checks if the specified token kind represents a keyword in the
304/// specified language.
305/// \returns Status of the keyword in the language.
307 tok::TokenKind K) {
308 switch (K) {
309#define KEYWORD(NAME, FLAGS) \
310 case tok::kw_##NAME: return getKeywordStatus(LangOpts, FLAGS);
311#include "clang/Basic/TokenKinds.def"
312 default: return KS_Disabled;
313 }
314}
315
316/// Returns true if the identifier represents a keyword in the
317/// specified language.
318bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) const {
319 switch (getTokenKwStatus(LangOpts, getTokenID())) {
320 case KS_Enabled:
321 case KS_Extension:
322 return true;
323 default:
324 return false;
325 }
326}
327
328/// Returns true if the identifier represents a C++ keyword in the
329/// specified language.
331 if (!LangOpts.CPlusPlus || !isKeyword(LangOpts))
332 return false;
333 // This is a C++ keyword if this identifier is not a keyword when checked
334 // using LangOptions without C++ support.
335 LangOptions LangOptsNoCPP = LangOpts;
336 LangOptsNoCPP.CPlusPlus = false;
337 LangOptsNoCPP.CPlusPlus11 = false;
338 LangOptsNoCPP.CPlusPlus20 = false;
339 return !isKeyword(LangOptsNoCPP);
340}
341
344 StringRef Name = getName();
345
346 // '_' is a reserved identifier, but its use is so common (e.g. to store
347 // ignored values) that we don't warn on it.
348 if (Name.size() <= 1)
350
351 // [lex.name] p3
352 if (Name[0] == '_') {
353
354 // Each name that begins with an underscore followed by an uppercase letter
355 // or another underscore is reserved.
356 if (Name[1] == '_')
358
359 if ('A' <= Name[1] && Name[1] <= 'Z')
360 return ReservedIdentifierStatus::
361 StartsWithUnderscoreFollowedByCapitalLetter;
362
363 // This is a bit misleading: it actually means it's only reserved if we're
364 // at global scope because it starts with an underscore.
366 }
367
368 // Each name that contains a double underscore (__) is reserved.
369 if (LangOpts.CPlusPlus && Name.contains("__"))
371
373}
374
377 StringRef Name = getName();
378
379 // Note: the diag::warn_deprecated_literal_operator_id diagnostic depends on
380 // this being the first check we do, so if this order changes, we have to fix
381 // that as well.
382 if (Name[0] != '_')
384
385 if (Name.contains("__"))
387
389}
390
392 StringRef Name = getName();
393 if (Name.size() >= 2 && Name.front() == '_' &&
394 (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')))
395 return Name.ltrim('_');
396 return Name;
397}
398
400 // We use a perfect hash function here involving the length of the keyword,
401 // the first and third character. For preprocessor ID's there are no
402 // collisions (if there were, the switch below would complain about duplicate
403 // case values). Note that this depends on 'if' being null terminated.
404
405#define HASH(LEN, FIRST, THIRD) \
406 (LEN << 6) + (((FIRST - 'a') - (THIRD - 'a')) & 63)
407#define CASE(LEN, FIRST, THIRD, NAME) \
408 case HASH(LEN, FIRST, THIRD): \
409 return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME
410
411 unsigned Len = getLength();
412 if (Len < 2) return tok::pp_not_keyword;
413 const char *Name = getNameStart();
414 switch (HASH(Len, Name[0], Name[2])) {
415 default: return tok::pp_not_keyword;
416 CASE( 2, 'i', '\0', if);
417 CASE( 4, 'e', 'i', elif);
418 CASE( 4, 'e', 's', else);
419 CASE( 4, 'l', 'n', line);
420 CASE( 4, 's', 'c', sccs);
421 CASE( 5, 'e', 'b', embed);
422 CASE( 5, 'e', 'd', endif);
423 CASE( 5, 'e', 'r', error);
424 CASE( 5, 'i', 'e', ident);
425 CASE( 5, 'i', 'd', ifdef);
426 CASE( 5, 'u', 'd', undef);
427
428 CASE( 6, 'a', 's', assert);
429 CASE( 6, 'd', 'f', define);
430 CASE( 6, 'i', 'n', ifndef);
431 CASE( 6, 'i', 'p', import);
432 CASE( 6, 'p', 'a', pragma);
433
434 CASE( 7, 'd', 'f', defined);
435 CASE( 7, 'e', 'i', elifdef);
436 CASE( 7, 'i', 'c', include);
437 CASE( 7, 'w', 'r', warning);
438
439 CASE( 8, 'e', 'i', elifndef);
440 CASE( 8, 'u', 'a', unassert);
441 CASE(12, 'i', 'c', include_next);
442
443 CASE(14, '_', 'p', __public_macro);
444
445 CASE(15, '_', 'p', __private_macro);
446
447 CASE(16, '_', 'i', __include_macros);
448#undef CASE
449#undef HASH
450 }
451}
452
453//===----------------------------------------------------------------------===//
454// Stats Implementation
455//===----------------------------------------------------------------------===//
456
457/// PrintStats - Print statistics about how well the identifier table is doing
458/// at hashing identifiers.
460 unsigned NumBuckets = HashTable.getNumBuckets();
461 unsigned NumIdentifiers = HashTable.getNumItems();
462 unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers;
463 unsigned AverageIdentifierSize = 0;
464 unsigned MaxIdentifierLength = 0;
465
466 // TODO: Figure out maximum times an identifier had to probe for -stats.
467 for (llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator>::const_iterator
468 I = HashTable.begin(), E = HashTable.end(); I != E; ++I) {
469 unsigned IdLen = I->getKeyLength();
470 AverageIdentifierSize += IdLen;
471 if (MaxIdentifierLength < IdLen)
472 MaxIdentifierLength = IdLen;
473 }
474
475 fprintf(stderr, "\n*** Identifier Table Stats:\n");
476 fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers);
477 fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets);
478 fprintf(stderr, "Hash density (#identifiers per bucket): %f\n",
479 NumIdentifiers/(double)NumBuckets);
480 fprintf(stderr, "Ave identifier length: %f\n",
481 (AverageIdentifierSize/(double)NumIdentifiers));
482 fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength);
483
484 // Compute statistics about the memory allocated for identifiers.
485 HashTable.getAllocator().PrintStats();
486}
487
488//===----------------------------------------------------------------------===//
489// SelectorTable Implementation
490//===----------------------------------------------------------------------===//
491
492unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) {
493 return DenseMapInfo<void*>::getHashValue(S.getAsOpaquePtr());
494}
495
497 assert(!Names.empty() && "must have >= 1 selector slots");
498 if (getNumArgs() != Names.size())
499 return false;
500 for (unsigned I = 0, E = Names.size(); I != E; ++I) {
501 if (getNameForSlot(I) != Names[I])
502 return false;
503 }
504 return true;
505}
506
507bool Selector::isUnarySelector(StringRef Name) const {
508 return isUnarySelector() && getNameForSlot(0) == Name;
509}
510
511unsigned Selector::getNumArgs() const {
512 unsigned IIF = getIdentifierInfoFlag();
513 if (IIF <= ZeroArg)
514 return 0;
515 if (IIF == OneArg)
516 return 1;
517 // We point to a MultiKeywordSelector.
518 MultiKeywordSelector *SI = getMultiKeywordSelector();
519 return SI->getNumArgs();
520}
521
522const IdentifierInfo *
523Selector::getIdentifierInfoForSlot(unsigned argIndex) const {
524 if (getIdentifierInfoFlag() < MultiArg) {
525 assert(argIndex == 0 && "illegal keyword index");
526 return getAsIdentifierInfo();
527 }
528
529 // We point to a MultiKeywordSelector.
530 MultiKeywordSelector *SI = getMultiKeywordSelector();
531 return SI->getIdentifierInfoForSlot(argIndex);
532}
533
534StringRef Selector::getNameForSlot(unsigned int argIndex) const {
535 const IdentifierInfo *II = getIdentifierInfoForSlot(argIndex);
536 return II ? II->getName() : StringRef();
537}
538
539std::string MultiKeywordSelector::getName() const {
541 llvm::raw_svector_ostream OS(Str);
542 for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) {
543 if (*I)
544 OS << (*I)->getName();
545 OS << ':';
546 }
547
548 return std::string(OS.str());
549}
550
551std::string Selector::getAsString() const {
552 if (isNull())
553 return "<null selector>";
554
555 if (getIdentifierInfoFlag() < MultiArg) {
556 const IdentifierInfo *II = getAsIdentifierInfo();
557
558 if (getNumArgs() == 0) {
559 assert(II && "If the number of arguments is 0 then II is guaranteed to "
560 "not be null.");
561 return std::string(II->getName());
562 }
563
564 if (!II)
565 return ":";
566
567 return II->getName().str() + ":";
568 }
569
570 // We have a multiple keyword selector.
571 return getMultiKeywordSelector()->getName();
572}
573
574void Selector::print(llvm::raw_ostream &OS) const {
575 OS << getAsString();
576}
577
578LLVM_DUMP_METHOD void Selector::dump() const { print(llvm::errs()); }
579
580/// Interpreting the given string using the normal CamelCase
581/// conventions, determine whether the given string starts with the
582/// given "word", which is assumed to end in a lowercase letter.
583static bool startsWithWord(StringRef name, StringRef word) {
584 if (name.size() < word.size()) return false;
585 return ((name.size() == word.size() || !isLowercase(name[word.size()])) &&
586 name.starts_with(word));
587}
588
589ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
590 const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
591 if (!first) return OMF_None;
592
593 StringRef name = first->getName();
594 if (sel.isUnarySelector()) {
595 if (name == "autorelease") return OMF_autorelease;
596 if (name == "dealloc") return OMF_dealloc;
597 if (name == "finalize") return OMF_finalize;
598 if (name == "release") return OMF_release;
599 if (name == "retain") return OMF_retain;
600 if (name == "retainCount") return OMF_retainCount;
601 if (name == "self") return OMF_self;
602 if (name == "initialize") return OMF_initialize;
603 }
604
605 if (name == "performSelector" || name == "performSelectorInBackground" ||
606 name == "performSelectorOnMainThread")
607 return OMF_performSelector;
608
609 // The other method families may begin with a prefix of underscores.
610 name = name.ltrim('_');
611
612 if (name.empty()) return OMF_None;
613 switch (name.front()) {
614 case 'a':
615 if (startsWithWord(name, "alloc")) return OMF_alloc;
616 break;
617 case 'c':
618 if (startsWithWord(name, "copy")) return OMF_copy;
619 break;
620 case 'i':
621 if (startsWithWord(name, "init")) return OMF_init;
622 break;
623 case 'm':
624 if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy;
625 break;
626 case 'n':
627 if (startsWithWord(name, "new")) return OMF_new;
628 break;
629 default:
630 break;
631 }
632
633 return OMF_None;
634}
635
637 const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
638 if (!first) return OIT_None;
639
640 StringRef name = first->getName();
641
642 if (name.empty()) return OIT_None;
643 switch (name.front()) {
644 case 'a':
645 if (startsWithWord(name, "array")) return OIT_Array;
646 break;
647 case 'd':
648 if (startsWithWord(name, "default")) return OIT_ReturnsSelf;
649 if (startsWithWord(name, "dictionary")) return OIT_Dictionary;
650 break;
651 case 's':
652 if (startsWithWord(name, "shared")) return OIT_ReturnsSelf;
653 if (startsWithWord(name, "standard")) return OIT_Singleton;
654 break;
655 case 'i':
656 if (startsWithWord(name, "init")) return OIT_Init;
657 break;
658 default:
659 break;
660 }
661 return OIT_None;
662}
663
664ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) {
665 const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
666 if (!first) return SFF_None;
667
668 StringRef name = first->getName();
669
670 switch (name.front()) {
671 case 'a':
672 if (name == "appendFormat") return SFF_NSString;
673 break;
674
675 case 'i':
676 if (name == "initWithFormat") return SFF_NSString;
677 break;
678
679 case 'l':
680 if (name == "localizedStringWithFormat") return SFF_NSString;
681 break;
682
683 case 's':
684 if (name == "stringByAppendingFormat" ||
685 name == "stringWithFormat") return SFF_NSString;
686 break;
687 }
688 return SFF_None;
689}
690
691namespace {
692
693struct SelectorTableImpl {
694 llvm::FoldingSet<MultiKeywordSelector> Table;
695 llvm::BumpPtrAllocator Allocator;
696};
697
698} // namespace
699
700static SelectorTableImpl &getSelectorTableImpl(void *P) {
701 return *static_cast<SelectorTableImpl*>(P);
702}
703
706 SmallString<64> SetterName("set");
707 SetterName += Name;
708 SetterName[3] = toUppercase(SetterName[3]);
709 return SetterName;
710}
711
714 SelectorTable &SelTable,
715 const IdentifierInfo *Name) {
716 IdentifierInfo *SetterName =
717 &Idents.get(constructSetterName(Name->getName()));
718 return SelTable.getUnarySelector(SetterName);
719}
720
722 StringRef Name = Sel.getNameForSlot(0);
723 assert(Name.starts_with("set") && "invalid setter name");
724 return (Twine(toLowercase(Name[3])) + Name.drop_front(4)).str();
725}
726
728 SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
729 return SelTabImpl.Allocator.getTotalMemory();
730}
731
733 const IdentifierInfo **IIV) {
734 if (nKeys < 2)
735 return Selector(IIV[0], nKeys);
736
737 SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
738
739 // Unique selector, to guarantee there is one per name.
740 llvm::FoldingSetNodeID ID;
741 MultiKeywordSelector::Profile(ID, IIV, nKeys);
742
743 void *InsertPos = nullptr;
744 if (MultiKeywordSelector *SI =
745 SelTabImpl.Table.FindNodeOrInsertPos(ID, InsertPos))
746 return Selector(SI);
747
748 // MultiKeywordSelector objects are not allocated with new because they have a
749 // variable size array (for parameter types) at the end of them.
750 unsigned Size = sizeof(MultiKeywordSelector) + nKeys*sizeof(IdentifierInfo *);
752 (MultiKeywordSelector *)SelTabImpl.Allocator.Allocate(
753 Size, alignof(MultiKeywordSelector));
754 new (SI) MultiKeywordSelector(nKeys, IIV);
755 SelTabImpl.Table.InsertNode(SI, InsertPos);
756 return Selector(SI);
757}
758
760 Impl = new SelectorTableImpl();
761}
762
766
768 switch (Operator) {
769 case OO_None:
771 return nullptr;
772
773#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
774 case OO_##Name: return Spelling;
775#include "clang/Basic/OperatorKinds.def"
776 }
777
778 llvm_unreachable("Invalid OverloadedOperatorKind!");
779}
780
782 bool isContextSensitive) {
783 switch (kind) {
785 return isContextSensitive ? "nonnull" : "_Nonnull";
786
788 return isContextSensitive ? "nullable" : "_Nullable";
789
791 assert(!isContextSensitive &&
792 "_Nullable_result isn't supported as context-sensitive keyword");
793 return "_Nullable_result";
794
796 return isContextSensitive ? "null_unspecified" : "_Null_unspecified";
797 }
798 llvm_unreachable("Unknown nullability kind.");
799}
800
801llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
802 NullabilityKind NK) {
803 switch (NK) {
805 return OS << "NonNull";
807 return OS << "Nullable";
809 return OS << "NullableResult";
811 return OS << "Unspecified";
812 }
813 llvm_unreachable("Unknown nullability kind.");
814}
815
818 const LangOptions &LangOpts) {
819 assert(II.isFutureCompatKeyword() && "diagnostic should not be needed");
820
821 unsigned Flags = llvm::StringSwitch<unsigned>(II.getName())
822#define KEYWORD(NAME, FLAGS) .Case(#NAME, FLAGS)
823#include "clang/Basic/TokenKinds.def"
824#undef KEYWORD
825 ;
826
827 if (LangOpts.CPlusPlus) {
828 if ((Flags & KEYCXX11) == KEYCXX11)
829 return diag::warn_cxx11_keyword;
830
831 // char8_t is not modeled as a CXX20_KEYWORD because it's not
832 // unconditionally enabled in C++20 mode. (It can be disabled
833 // by -fno-char8_t.)
834 if (((Flags & KEYCXX20) == KEYCXX20) ||
835 ((Flags & CHAR8SUPPORT) == CHAR8SUPPORT))
836 return diag::warn_cxx20_keyword;
837 } else {
838 if ((Flags & KEYC99) == KEYC99)
839 return diag::warn_c99_keyword;
840 if ((Flags & KEYC23) == KEYC23)
841 return diag::warn_c23_keyword;
842 }
843
844 llvm_unreachable(
845 "Keyword not known to come from a newer Standard or proposed Standard");
846}
FormatToken * Next
The next token in the unwrapped line.
static void AddObjCKeyword(StringRef Name, tok::ObjCKeywordKind ObjCID, IdentifierTable &Table)
AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or "property".
static bool IsKeywordInCpp(unsigned Flags)
static void AddCXXOperatorKeyword(StringRef Keyword, tok::TokenKind TokenCode, IdentifierTable &Table)
AddCXXOperatorKeyword - Register a C++ operator keyword alternative representations.
static void AddNotableIdentifier(StringRef Name, tok::NotableIdentifierKind BTID, IdentifierTable &Table)
static void MarkIdentifierAsKeywordInCpp(IdentifierTable &Table, StringRef Name)
static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts, TokenKey Flag)
static KeywordStatus getTokenKwStatus(const LangOptions &LangOpts, tok::TokenKind K)
Checks if the specified token kind represents a keyword in the specified language.
static bool startsWithWord(StringRef name, StringRef word)
Interpreting the given string using the normal CamelCase conventions, determine whether the given str...
#define CASE(LEN, FIRST, THIRD, NAME)
static void AddKeyword(StringRef Keyword, tok::TokenKind TokenCode, unsigned Flags, const LangOptions &LangOpts, IdentifierTable &Table)
AddKeyword - This method is used to associate a token ID with specific identifiers because they are l...
static SelectorTableImpl & getSelectorTableImpl(void *P)
#define HASH(LEN, FIRST, THIRD)
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
Defines the clang::LangOptions interface.
Defines an enumeration for C++ overloaded operators.
Defines various enumerations that describe declaration and type specifiers.
Enumerates target-specific builtins in their own namespaces within namespace clang.
Defines the clang::TokenKind enum and support functions.
Provides lookups to, and iteration over, IdentiferInfo objects.
virtual IdentifierIterator * getIdentifiers()
Retrieve an iterator into the set of all identifiers known to this identifier lookup source.
One of these records is kept for each identifier that is lexed.
bool isCPlusPlusKeyword(const LangOptions &LangOpts) const
Return true if this token is a C++ keyword in the specified language.
unsigned getLength() const
Efficiently return the length of this identifier info.
void setModulesImport(bool I)
Set whether this identifier is the contextual keyword import.
void setNotableIdentifierID(unsigned ID)
void setIsExtensionToken(bool Val)
tok::PPKeywordKind getPPKeywordID() const
Return the preprocessor keyword ID for this identifier.
tok::TokenKind getTokenID() const
If this is a source-language token (e.g.
void setObjCKeywordID(tok::ObjCKeywordKind ID)
void setHandleIdentifierCase(bool Val=true)
void setIsKeywordInCPlusPlus(bool Val=true)
const char * getNameStart() const
Return the beginning of the actual null-terminated string for this identifier.
bool isKeyword(const LangOptions &LangOpts) const
Return true if this token is a keyword in the specified language.
ReservedIdentifierStatus isReserved(const LangOptions &LangOpts) const
Determine whether this is a name reserved for the implementation (C99 7.1.3, C++ [lib....
void setIsCPlusPlusOperatorKeyword(bool Val=true)
isCPlusPlusOperatorKeyword/setIsCPlusPlusOperatorKeyword controls whether this identifier is a C++ al...
ReservedLiteralSuffixIdStatus isReservedLiteralSuffixId() const
Determine whether this is a name reserved for future standardization or the implementation (C++ [usrl...
void setIsFutureCompatKeyword(bool Val)
StringRef deuglifiedName() const
If the identifier is an "uglified" reserved name, return a cleaned form.
StringRef getName() const
Return the actual identifier string.
bool isFutureCompatKeyword() const
is/setIsFutureCompatKeyword - Initialize information about whether or not this language token is a ke...
An iterator that walks over all of the known identifiers in the lookup table.
Implements an efficient mapping from strings to IdentifierInfo nodes.
IdentifierTable(IdentifierInfoLookup *ExternalLookup=nullptr)
Create the identifier table.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
void PrintStats() const
Print some statistics to stderr that indicate how well the hashing is doing.
void AddKeywords(const LangOptions &LangOpts)
Populate the identifier table with info about the language keywords for the language specified by Lan...
diag::kind getFutureCompatDiagKind(const IdentifierInfo &II, const LangOptions &LangOpts)
Returns the correct diagnostic to issue for a future-compat diagnostic warning.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
bool isCompatibleWithMSVC(MSVCMajorVersion MajorVersion) const
bool isSYCL() const
One of these variable length records is kept for each selector containing more than one keyword.
keyword_iterator keyword_end() const
const IdentifierInfo *const * keyword_iterator
static void Profile(llvm::FoldingSetNodeID &ID, keyword_iterator ArgTys, unsigned NumArgs)
keyword_iterator keyword_begin() const
const IdentifierInfo * getIdentifierInfoForSlot(unsigned i) const
static std::string getPropertyNameFromSetterSelector(Selector Sel)
Return the property name for the given setter selector.
static Selector constructSetterSelector(IdentifierTable &Idents, SelectorTable &SelTable, const IdentifierInfo *Name)
Return the default setter selector for the given identifier.
size_t getTotalMemory() const
Return the total amount of memory allocated for managing selectors.
Selector getSelector(unsigned NumArgs, const IdentifierInfo **IIV)
Can create any sort of selector.
Selector getUnarySelector(const IdentifierInfo *ID)
static SmallString< 64 > constructSetterName(StringRef Name)
Return the default setter name for the given identifier.
Smart pointer class that efficiently represents Objective-C method names.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
const IdentifierInfo * getIdentifierInfoForSlot(unsigned argIndex) const
Retrieve the identifier at a given position in the selector.
std::string getAsString() const
Derive the full selector name (e.g.
void print(llvm::raw_ostream &OS) const
Prints the full selector name (e.g. "foo:bar:").
void * getAsOpaquePtr() const
bool isKeywordSelector() const
static ObjCInstanceTypeFamily getInstTypeMethodFamily(Selector sel)
bool isUnarySelector() const
bool isNull() const
Determine whether this is the empty selector.
unsigned getNumArgs() const
unsigned getNumArgs() const
Return the number of arguments in an ObjC selector.
unsigned kind
All of the diagnostics that can be emitted by the frontend.
NotableIdentifierKind
Provides a namespace for notable identifers such as float_t and double_t.
Definition TokenKinds.h:49
ObjCKeywordKind
Provides a namespace for Objective-C keywords which start with an '@'.
Definition TokenKinds.h:41
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
Definition TokenKinds.h:25
PPKeywordKind
Provides a namespace for preprocessor keywords which start with a '#' at the beginning of the line.
Definition TokenKinds.h:33
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr, CxxCtorInitializer, and TypeLoc) selects th...
The JSON file list parser is used to communicate input to InstallAPI.
TokenKey
Constants for TokenKinds.def.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
@ OO_None
Not an overloaded operator.
@ NUM_OVERLOADED_OPERATORS
KeywordStatus getKeywordStatus(const LangOptions &LangOpts, unsigned Flags)
Translates flags as specified in TokenKinds.def into keyword status in the given language standard.
NullabilityKind
Describes the nullability of a particular type.
Definition Specifiers.h:348
@ Nullable
Values of this type can be null.
Definition Specifiers.h:352
@ Unspecified
Whether values of this type can be null is (explicitly) unspecified.
Definition Specifiers.h:357
@ NonNull
Values of this type can never be null.
Definition Specifiers.h:350
LLVM_READONLY char toLowercase(char c)
Converts the given ASCII character to its lowercase equivalent.
Definition CharInfo.h:224
ObjCMethodFamily
A family of Objective-C methods.
@ OMF_performSelector
@ OMF_None
No particular method family.
llvm::StringRef getNullabilitySpelling(NullabilityKind kind, bool isContextSensitive=false)
Retrieve the spelling of the given nullability kind.
ObjCInstanceTypeFamily
A family of Objective-C methods.
ReservedLiteralSuffixIdStatus
LLVM_READONLY bool isLowercase(unsigned char c)
Return true if this character is a lowercase ASCII letter: [a-z].
Definition CharInfo.h:120
LLVM_READONLY char toUppercase(char c)
Converts the given ASCII character to its uppercase equivalent.
Definition CharInfo.h:233
@ Keyword
The name has been typo-corrected to a keyword.
Definition Sema.h:560
static constexpr int InterestingIdentifierBits
KeywordStatus
How a keyword is treated in the selected standard.
static constexpr uint64_t LargestBuiltinID
const StreamingDiagnostic & operator<<(const StreamingDiagnostic &DB, const ConceptReference *C)
Insertion operator for diagnostics.
const char * getOperatorSpelling(OverloadedOperatorKind Operator)
Retrieve the spelling of the given overloaded operator, without the preceding "operator" keyword.
ReservedIdentifierStatus