/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Basic/IdentifierTable.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
14 | | #include "clang/Basic/IdentifierTable.h" |
15 | | #include "clang/Basic/CharInfo.h" |
16 | | #include "clang/Basic/LangOptions.h" |
17 | | #include "clang/Basic/OperatorKinds.h" |
18 | | #include "clang/Basic/Specifiers.h" |
19 | | #include "clang/Basic/TargetBuiltins.h" |
20 | | #include "clang/Basic/TokenKinds.h" |
21 | | #include "llvm/ADT/DenseMapInfo.h" |
22 | | #include "llvm/ADT/FoldingSet.h" |
23 | | #include "llvm/ADT/SmallString.h" |
24 | | #include "llvm/ADT/StringMap.h" |
25 | | #include "llvm/ADT/StringRef.h" |
26 | | #include "llvm/Support/Allocator.h" |
27 | | #include "llvm/Support/ErrorHandling.h" |
28 | | #include "llvm/Support/raw_ostream.h" |
29 | | #include <cassert> |
30 | | #include <cstdio> |
31 | | #include <cstring> |
32 | | #include <string> |
33 | | |
34 | | using namespace clang; |
35 | | |
36 | | // A check to make sure the ObjCOrBuiltinID has sufficient room to store the |
37 | | // largest possible target/aux-target combination. If we exceed this, we likely |
38 | | // need to just change the ObjCOrBuiltinIDBits value in IdentifierTable.h. |
39 | | static_assert(2 * LargestBuiltinID < (2 << (ObjCOrBuiltinIDBits - 1)), |
40 | | "Insufficient ObjCOrBuiltinID Bits"); |
41 | | |
42 | | //===----------------------------------------------------------------------===// |
43 | | // IdentifierTable Implementation |
44 | | //===----------------------------------------------------------------------===// |
45 | | |
46 | 384 | IdentifierIterator::~IdentifierIterator() = default; |
47 | | |
48 | 13.2k | IdentifierInfoLookup::~IdentifierInfoLookup() = default; |
49 | | |
50 | | namespace { |
51 | | |
52 | | /// A simple identifier lookup iterator that represents an |
53 | | /// empty sequence of identifiers. |
54 | | class EmptyLookupIterator : public IdentifierIterator |
55 | | { |
56 | | public: |
57 | 0 | StringRef Next() override { return StringRef(); } |
58 | | }; |
59 | | |
60 | | } // namespace |
61 | | |
62 | 0 | IdentifierIterator *IdentifierInfoLookup::getIdentifiers() { |
63 | 0 | return new EmptyLookupIterator(); |
64 | 0 | } |
65 | | |
66 | | IdentifierTable::IdentifierTable(IdentifierInfoLookup *ExternalLookup) |
67 | | : HashTable(8192), // Start with space for 8K identifiers. |
68 | 171k | ExternalLookup(ExternalLookup) {} |
69 | | |
70 | | IdentifierTable::IdentifierTable(const LangOptions &LangOpts, |
71 | | IdentifierInfoLookup *ExternalLookup) |
72 | 80.5k | : IdentifierTable(ExternalLookup) { |
73 | | // Populate the identifier table with info about keywords for the current |
74 | | // language. |
75 | 80.5k | AddKeywords(LangOpts); |
76 | 80.5k | } Unexecuted instantiation: clang::IdentifierTable::IdentifierTable(clang::LangOptions const&, clang::IdentifierInfoLookup*) clang::IdentifierTable::IdentifierTable(clang::LangOptions const&, clang::IdentifierInfoLookup*) Line | Count | Source | 72 | 80.5k | : IdentifierTable(ExternalLookup) { | 73 | | // Populate the identifier table with info about keywords for the current | 74 | | // language. | 75 | 80.5k | AddKeywords(LangOpts); | 76 | 80.5k | } |
|
77 | | |
78 | | //===----------------------------------------------------------------------===// |
79 | | // Language Keyword Implementation |
80 | | //===----------------------------------------------------------------------===// |
81 | | |
82 | | // Constants for TokenKinds.def |
83 | | namespace { |
84 | | |
85 | | enum { |
86 | | KEYC99 = 0x1, |
87 | | KEYCXX = 0x2, |
88 | | KEYCXX11 = 0x4, |
89 | | KEYGNU = 0x8, |
90 | | KEYMS = 0x10, |
91 | | BOOLSUPPORT = 0x20, |
92 | | KEYALTIVEC = 0x40, |
93 | | KEYNOCXX = 0x80, |
94 | | KEYBORLAND = 0x100, |
95 | | KEYOPENCLC = 0x200, |
96 | | KEYC11 = 0x400, |
97 | | KEYNOMS18 = 0x800, |
98 | | KEYNOOPENCL = 0x1000, |
99 | | WCHARSUPPORT = 0x2000, |
100 | | HALFSUPPORT = 0x4000, |
101 | | CHAR8SUPPORT = 0x8000, |
102 | | KEYCONCEPTS = 0x10000, |
103 | | KEYOBJC = 0x20000, |
104 | | KEYZVECTOR = 0x40000, |
105 | | KEYCOROUTINES = 0x80000, |
106 | | KEYMODULES = 0x100000, |
107 | | KEYCXX20 = 0x200000, |
108 | | KEYOPENCLCXX = 0x400000, |
109 | | KEYMSCOMPAT = 0x800000, |
110 | | KEYSYCL = 0x1000000, |
111 | | KEYCUDA = 0x2000000, |
112 | | KEYMAX = KEYCUDA, // The maximum key |
113 | | KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20, |
114 | | KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 & |
115 | | ~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude. |
116 | | }; |
117 | | |
118 | | /// How a keyword is treated in the selected standard. |
119 | | enum KeywordStatus { |
120 | | KS_Disabled, // Disabled |
121 | | KS_Extension, // Is an extension |
122 | | KS_Enabled, // Enabled |
123 | | KS_Future // Is a keyword in future standard |
124 | | }; |
125 | | |
126 | | } // namespace |
127 | | |
128 | | /// Translates flags as specified in TokenKinds.def into keyword status |
129 | | /// in the given language standard. |
130 | | static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, |
131 | 60.1M | unsigned Flags) { |
132 | 60.1M | if (Flags == KEYALL) return KS_Enabled18.8M ; |
133 | 41.3M | if (LangOpts.CPlusPlus && (Flags & KEYCXX)35.5M ) return KS_Enabled15.0M ; |
134 | 26.2M | if (LangOpts.CPlusPlus11 && (Flags & KEYCXX11)18.2M ) return KS_Enabled1.32M ; |
135 | 24.8M | if (LangOpts.CPlusPlus20 && (Flags & KEYCXX20)8.93M ) return KS_Enabled487k ; |
136 | 24.4M | if (LangOpts.C99 && (Flags & KEYC99)13.2M ) return KS_Enabled131k ; |
137 | 24.2M | if (LangOpts.GNUKeywords && (Flags & KEYGNU)17.9M ) return KS_Extension152k ; |
138 | 24.1M | if (LangOpts.MicrosoftExt && (Flags & KEYMS)9.68M ) return KS_Extension3.61M ; |
139 | 20.5M | if (LangOpts.MSVCCompat && (Flags & KEYMSCOMPAT)1.21M ) return KS_Enabled155k ; |
140 | 20.3M | if (LangOpts.Borland && (Flags & KEYBORLAND)891 ) return KS_Extension54 ; |
141 | 20.3M | if (LangOpts.Bool && (Flags & BOOLSUPPORT)14.9M ) return KS_Enabled446k ; |
142 | 19.9M | if (LangOpts.Half && (Flags & HALFSUPPORT)207k ) return KS_Enabled978 ; |
143 | 19.9M | if (LangOpts.WChar && (Flags & WCHARSUPPORT)9.76M ) return KS_Enabled82.7k ; |
144 | 19.8M | if (LangOpts.Char8 && (Flags & CHAR8SUPPORT)4.99M ) return KS_Enabled69.6k ; |
145 | 19.7M | if (LangOpts.AltiVec && (Flags & KEYALTIVEC)65.0k ) return KS_Enabled1.31k ; |
146 | 19.7M | if (LangOpts.ZVector && (Flags & KEYZVECTOR)2.49k ) return KS_Enabled39 ; |
147 | 19.7M | if (LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus200k && (Flags & KEYOPENCLC)181k ) |
148 | 25.8k | return KS_Enabled; |
149 | 19.7M | if (LangOpts.OpenCLCPlusPlus && (Flags & KEYOPENCLCXX)18.4k ) return KS_Enabled4.95k ; |
150 | 19.7M | if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)5.51M ) return KS_Enabled118k ; |
151 | 19.5M | if (LangOpts.C11 && (Flags & KEYC11)4.44M ) return KS_Enabled0 ; |
152 | | // We treat bridge casts as objective-C keywords so we can warn on them |
153 | | // in non-arc mode. |
154 | 19.5M | if (LangOpts.ObjC && (Flags & KEYOBJC)9.19M ) return KS_Enabled682k ; |
155 | 18.9M | if (LangOpts.CPlusPlus20 && (Flags & KEYCONCEPTS)4.48M ) return KS_Enabled0 ; |
156 | 18.9M | if (LangOpts.Coroutines && (Flags & KEYCOROUTINES)449k ) return KS_Enabled177 ; |
157 | 18.9M | if (LangOpts.ModulesTS && (Flags & KEYMODULES)17.6k ) return KS_Enabled286 ; |
158 | 18.9M | if (LangOpts.CPlusPlus && (Flags & KEYALLCXX)13.5M ) return KS_Future707k ; |
159 | 18.2M | if (LangOpts.CPlusPlus && !LangOpts.CPlusPlus2012.8M && (Flags & CHAR8SUPPORT)8.37M ) |
160 | 78.4k | return KS_Future; |
161 | 18.1M | if (LangOpts.isSYCL() && (Flags & KEYSYCL)4.60k ) |
162 | 39 | return KS_Enabled; |
163 | 18.1M | if (LangOpts.CUDA && (Flags & KEYCUDA)47.6k ) |
164 | 417 | return KS_Enabled; |
165 | 18.1M | return KS_Disabled; |
166 | 18.1M | } |
167 | | |
168 | | /// AddKeyword - This method is used to associate a token ID with specific |
169 | | /// identifiers because they are language keywords. This causes the lexer to |
170 | | /// automatically map matching identifiers to specialized token codes. |
171 | | static void AddKeyword(StringRef Keyword, |
172 | | tok::TokenKind TokenCode, unsigned Flags, |
173 | 59.6M | const LangOptions &LangOpts, IdentifierTable &Table) { |
174 | 59.6M | KeywordStatus AddResult = getKeywordStatus(LangOpts, Flags); |
175 | | |
176 | | // Don't add this keyword under MSVCCompat. |
177 | 59.6M | if (LangOpts.MSVCCompat && (Flags & KEYNOMS18)4.37M && |
178 | 59.6M | !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015)25.1k ) |
179 | 5.90k | return; |
180 | | |
181 | | // Don't add this keyword under OpenCL. |
182 | 59.6M | if (LangOpts.OpenCL && (Flags & KEYNOOPENCL)324k ) |
183 | 934 | return; |
184 | | |
185 | | // Don't add this keyword if disabled in this language. |
186 | 59.6M | if (AddResult == KS_Disabled) return17.9M ; |
187 | | |
188 | 41.6M | IdentifierInfo &Info = |
189 | 41.6M | Table.get(Keyword, AddResult == KS_Future ? tok::identifier783k : TokenCode40.8M ); |
190 | 41.6M | Info.setIsExtensionToken(AddResult == KS_Extension); |
191 | 41.6M | Info.setIsFutureCompatKeyword(AddResult == KS_Future); |
192 | 41.6M | } |
193 | | |
194 | | /// AddCXXOperatorKeyword - Register a C++ operator keyword alternative |
195 | | /// representations. |
196 | | static void AddCXXOperatorKeyword(StringRef Keyword, |
197 | | tok::TokenKind TokenCode, |
198 | 1.31M | IdentifierTable &Table) { |
199 | 1.31M | IdentifierInfo &Info = Table.get(Keyword, TokenCode); |
200 | 1.31M | Info.setIsCPlusPlusOperatorKeyword(); |
201 | 1.31M | } |
202 | | |
203 | | /// AddObjCKeyword - Register an Objective-C \@keyword like "class" "selector" |
204 | | /// or "property". |
205 | | static void AddObjCKeyword(StringRef Name, |
206 | | tok::ObjCKeywordKind ObjCID, |
207 | 2.63M | IdentifierTable &Table) { |
208 | 2.63M | Table.get(Name).setObjCKeywordID(ObjCID); |
209 | 2.63M | } |
210 | | |
211 | | /// AddKeywords - Add all keywords to the symbol table. |
212 | | /// |
213 | 171k | void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { |
214 | | // Add keywords and tokens for the current language. |
215 | 171k | #define KEYWORD(NAME, FLAGS) \ |
216 | 47.8M | AddKeyword(StringRef(#NAME), tok::kw_ ## NAME, \ |
217 | 47.8M | FLAGS, LangOpts, *this); |
218 | 171k | #define ALIAS(NAME, TOK, FLAGS) \ |
219 | 11.6M | AddKeyword(StringRef(NAME), tok::kw_ ## TOK, \ |
220 | 11.6M | FLAGS, LangOpts, *this); |
221 | 171k | #define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \ |
222 | 1.88M | if (LangOpts.CXXOperatorNames) \ |
223 | 1.88M | AddCXXOperatorKeyword(StringRef(#NAME), tok::ALIAS, *this)1.31M ; |
224 | 171k | #define OBJC_AT_KEYWORD(NAME) \ |
225 | 4.63M | if (LangOpts.ObjC) \ |
226 | 4.63M | AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this)2.63M ; |
227 | 171k | #define TESTING_KEYWORD(NAME, FLAGS) |
228 | 171k | #include "clang/Basic/TokenKinds.def" |
229 | | |
230 | 171k | if (LangOpts.ParseUnknownAnytype) |
231 | 9 | AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL, |
232 | 9 | LangOpts, *this); |
233 | | |
234 | 171k | if (LangOpts.DeclSpecKeyword) |
235 | 79.1k | AddKeyword("__declspec", tok::kw___declspec, KEYALL, LangOpts, *this); |
236 | | |
237 | 171k | if (LangOpts.IEEE128) |
238 | 4.09k | AddKeyword("__ieee128", tok::kw___float128, KEYALL, LangOpts, *this); |
239 | | |
240 | | // Add the 'import' contextual keyword. |
241 | 171k | get("import").setModulesImport(true); |
242 | 171k | } |
243 | | |
244 | | /// Checks if the specified token kind represents a keyword in the |
245 | | /// specified language. |
246 | | /// \returns Status of the keyword in the language. |
247 | | static KeywordStatus getTokenKwStatus(const LangOptions &LangOpts, |
248 | 4.66M | tok::TokenKind K) { |
249 | 4.66M | switch (K) { |
250 | 0 | #define KEYWORD(NAME, FLAGS) \ |
251 | 517k | case tok::kw_##NAME: return getKeywordStatus(LangOpts, FLAGS); |
252 | 0 | #include "clang/Basic/TokenKinds.def" |
253 | 4.14M | default: return KS_Disabled; |
254 | 4.66M | } |
255 | 4.66M | } |
256 | | |
257 | | /// Returns true if the identifier represents a keyword in the |
258 | | /// specified language. |
259 | 4.66M | bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) const { |
260 | 4.66M | switch (getTokenKwStatus(LangOpts, getTokenID())) { |
261 | 371k | case KS_Enabled: |
262 | 378k | case KS_Extension: |
263 | 378k | return true; |
264 | 4.28M | default: |
265 | 4.28M | return false; |
266 | 4.66M | } |
267 | 4.66M | } |
268 | | |
269 | | /// Returns true if the identifier represents a C++ keyword in the |
270 | | /// specified language. |
271 | 379k | bool IdentifierInfo::isCPlusPlusKeyword(const LangOptions &LangOpts) const { |
272 | 379k | if (!LangOpts.CPlusPlus || !isKeyword(LangOpts)379k ) |
273 | 125k | return false; |
274 | | // This is a C++ keyword if this identifier is not a keyword when checked |
275 | | // using LangOptions without C++ support. |
276 | 253k | LangOptions LangOptsNoCPP = LangOpts; |
277 | 253k | LangOptsNoCPP.CPlusPlus = false; |
278 | 253k | LangOptsNoCPP.CPlusPlus11 = false; |
279 | 253k | LangOptsNoCPP.CPlusPlus20 = false; |
280 | 253k | return !isKeyword(LangOptsNoCPP); |
281 | 379k | } |
282 | | |
283 | | ReservedIdentifierStatus |
284 | 51.1M | IdentifierInfo::isReserved(const LangOptions &LangOpts) const { |
285 | 51.1M | StringRef Name = getName(); |
286 | | |
287 | | // '_' is a reserved identifier, but its use is so common (e.g. to store |
288 | | // ignored values) that we don't warn on it. |
289 | 51.1M | if (Name.size() <= 1) |
290 | 645k | return ReservedIdentifierStatus::NotReserved; |
291 | | |
292 | | // [lex.name] p3 |
293 | 50.5M | if (Name[0] == '_') { |
294 | | |
295 | | // Each name that begins with an underscore followed by an uppercase letter |
296 | | // or another underscore is reserved. |
297 | 14.5M | if (Name[1] == '_') |
298 | 9.99M | return ReservedIdentifierStatus::StartsWithDoubleUnderscore; |
299 | | |
300 | 4.57M | if ('A' <= Name[1] && Name[1] <= 'Z'4.56M ) |
301 | 3.16M | return ReservedIdentifierStatus:: |
302 | 3.16M | StartsWithUnderscoreFollowedByCapitalLetter; |
303 | | |
304 | | // This is a bit misleading: it actually means it's only reserved if we're |
305 | | // at global scope because it starts with an underscore. |
306 | 1.41M | return ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope; |
307 | 4.57M | } |
308 | | |
309 | | // Each name that contains a double underscore (__) is reserved. |
310 | 35.9M | if (LangOpts.CPlusPlus && Name.contains("__")15.7M ) |
311 | 30.3k | return ReservedIdentifierStatus::ContainsDoubleUnderscore; |
312 | | |
313 | 35.9M | return ReservedIdentifierStatus::NotReserved; |
314 | 35.9M | } |
315 | | |
316 | 2.08k | StringRef IdentifierInfo::deuglifiedName() const { |
317 | 2.08k | StringRef Name = getName(); |
318 | 2.08k | if (Name.size() >= 2 && Name.front() == '_'311 && |
319 | 2.08k | (14 Name[1] == '_'14 || (8 Name[1] >= 'A'8 && Name[1] <= 'Z'8 ))) |
320 | 14 | return Name.ltrim('_'); |
321 | 2.06k | return Name; |
322 | 2.08k | } |
323 | | |
324 | 113M | tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { |
325 | | // We use a perfect hash function here involving the length of the keyword, |
326 | | // the first and third character. For preprocessor ID's there are no |
327 | | // collisions (if there were, the switch below would complain about duplicate |
328 | | // case values). Note that this depends on 'if' being null terminated. |
329 | | |
330 | 113M | #define HASH(LEN, FIRST, THIRD) \ |
331 | 181M | (LEN << 5) + (((FIRST-'a') + (THIRD-'a')) & 31) |
332 | 113M | #define CASE(LEN, FIRST, THIRD, NAME) \ |
333 | 113M | case 68.2M HASH68.2M (LEN, FIRST, THIRD): \ |
334 | 68.2M | return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword648k : tok::pp_67.6M ## NAME |
335 | | |
336 | 113M | unsigned Len = getLength(); |
337 | 113M | if (Len < 2) return tok::pp_not_keyword127k ; |
338 | 113M | const char *Name = getNameStart(); |
339 | 113M | switch (HASH(Len, Name[0], Name[2])) { |
340 | 45.0M | default: return tok::pp_not_keyword; |
341 | 2.40M | CASE(0 2, 'i', '\0', if); |
342 | 263k | CASE(0 4, 'e', 'i', elif); |
343 | 1.27M | CASE(0 4, 'e', 's', else); |
344 | 61.4k | CASE(0 4, 'l', 'n', line); |
345 | 6.46k | CASE(0 4, 's', 'c', sccs); |
346 | 6.11M | CASE(0 5, 'e', 'd', endif); |
347 | 13.1k | CASE(0 5, 'e', 'r', error); |
348 | 3.49k | CASE(0 5, 'i', 'e', ident); |
349 | 1.25M | CASE(0 5, 'i', 'd', ifdef); |
350 | 130k | CASE(0 5, 'u', 'd', undef); |
351 | | |
352 | 33.1k | CASE(0 6, 'a', 's', assert); |
353 | 45.2M | CASE(0 6, 'd', 'f', define); |
354 | 4.99M | CASE(0 6, 'i', 'n', ifndef); |
355 | 289k | CASE(0 6, 'i', 'p', import); |
356 | 846k | CASE(0 6, 'p', 'a', pragma); |
357 | | |
358 | 11.4k | CASE(0 7, 'd', 'f', defined); |
359 | 9.22k | CASE(0 7, 'e', 'i', elifdef); |
360 | 4.89M | CASE(0 7, 'i', 'c', include); |
361 | 1.39k | CASE(0 7, 'w', 'r', warning); |
362 | | |
363 | 35.7k | CASE(0 8, 'e', 'i', elifndef); |
364 | 5.67k | CASE(0 8, 'u', 'a', unassert); |
365 | 41.6k | CASE(0 12, 'i', 'c', include_next); |
366 | | |
367 | 5.05k | CASE(0 14, '_', 'p', __public_macro); |
368 | | |
369 | 88.7k | CASE(0 15, '_', 'p', __private_macro); |
370 | | |
371 | 113M | CASE235k (16, '_', 'i', __include_macros); |
372 | 113M | #undef CASE |
373 | 113M | #undef HASH |
374 | 113M | } |
375 | 113M | } |
376 | | |
377 | | //===----------------------------------------------------------------------===// |
378 | | // Stats Implementation |
379 | | //===----------------------------------------------------------------------===// |
380 | | |
381 | | /// PrintStats - Print statistics about how well the identifier table is doing |
382 | | /// at hashing identifiers. |
383 | 4 | void IdentifierTable::PrintStats() const { |
384 | 4 | unsigned NumBuckets = HashTable.getNumBuckets(); |
385 | 4 | unsigned NumIdentifiers = HashTable.getNumItems(); |
386 | 4 | unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers; |
387 | 4 | unsigned AverageIdentifierSize = 0; |
388 | 4 | unsigned MaxIdentifierLength = 0; |
389 | | |
390 | | // TODO: Figure out maximum times an identifier had to probe for -stats. |
391 | 4 | for (llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator>::const_iterator |
392 | 7.73k | I = HashTable.begin(), E = HashTable.end(); I != E; ++I7.72k ) { |
393 | 7.72k | unsigned IdLen = I->getKeyLength(); |
394 | 7.72k | AverageIdentifierSize += IdLen; |
395 | 7.72k | if (MaxIdentifierLength < IdLen) |
396 | 22 | MaxIdentifierLength = IdLen; |
397 | 7.72k | } |
398 | | |
399 | 4 | fprintf(stderr, "\n*** Identifier Table Stats:\n"); |
400 | 4 | fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers); |
401 | 4 | fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets); |
402 | 4 | fprintf(stderr, "Hash density (#identifiers per bucket): %f\n", |
403 | 4 | NumIdentifiers/(double)NumBuckets); |
404 | 4 | fprintf(stderr, "Ave identifier length: %f\n", |
405 | 4 | (AverageIdentifierSize/(double)NumIdentifiers)); |
406 | 4 | fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength); |
407 | | |
408 | | // Compute statistics about the memory allocated for identifiers. |
409 | 4 | HashTable.getAllocator().PrintStats(); |
410 | 4 | } |
411 | | |
412 | | //===----------------------------------------------------------------------===// |
413 | | // SelectorTable Implementation |
414 | | //===----------------------------------------------------------------------===// |
415 | | |
416 | 6.79M | unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) { |
417 | 6.79M | return DenseMapInfo<void*>::getHashValue(S.getAsOpaquePtr()); |
418 | 6.79M | } |
419 | | |
420 | | namespace clang { |
421 | | |
422 | | /// One of these variable length records is kept for each |
423 | | /// selector containing more than one keyword. We use a folding set |
424 | | /// to unique aggregate names (keyword selectors in ObjC parlance). Access to |
425 | | /// this class is provided strictly through Selector. |
426 | | class alignas(IdentifierInfoAlignment) MultiKeywordSelector |
427 | | : public detail::DeclarationNameExtra, |
428 | | public llvm::FoldingSetNode { |
429 | 0 | MultiKeywordSelector(unsigned nKeys) : DeclarationNameExtra(nKeys) {} |
430 | | |
431 | | public: |
432 | | // Constructor for keyword selectors. |
433 | | MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) |
434 | 243k | : DeclarationNameExtra(nKeys) { |
435 | 243k | assert((nKeys > 1) && "not a multi-keyword selector"); |
436 | | |
437 | | // Fill in the trailing keyword array. |
438 | 0 | IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(this + 1); |
439 | 905k | for (unsigned i = 0; i != nKeys; ++i661k ) |
440 | 661k | KeyInfo[i] = IIV[i]; |
441 | 243k | } |
442 | | |
443 | | // getName - Derive the full selector name and return it. |
444 | | std::string getName() const; |
445 | | |
446 | | using DeclarationNameExtra::getNumArgs; |
447 | | |
448 | | using keyword_iterator = IdentifierInfo *const *; |
449 | | |
450 | 1.72M | keyword_iterator keyword_begin() const { |
451 | 1.72M | return reinterpret_cast<keyword_iterator>(this + 1); |
452 | 1.72M | } |
453 | | |
454 | 27.3k | keyword_iterator keyword_end() const { |
455 | 27.3k | return keyword_begin() + getNumArgs(); |
456 | 27.3k | } |
457 | | |
458 | 1.03M | IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { |
459 | 1.03M | assert(i < getNumArgs() && "getIdentifierInfoForSlot(): illegal index"); |
460 | 0 | return keyword_begin()[i]; |
461 | 1.03M | } |
462 | | |
463 | | static void Profile(llvm::FoldingSetNodeID &ID, keyword_iterator ArgTys, |
464 | 957k | unsigned NumArgs) { |
465 | 957k | ID.AddInteger(NumArgs); |
466 | 3.48M | for (unsigned i = 0; i != NumArgs; ++i2.52M ) |
467 | 2.52M | ID.AddPointer(ArgTys[i]); |
468 | 957k | } |
469 | | |
470 | 633k | void Profile(llvm::FoldingSetNodeID &ID) { |
471 | 633k | Profile(ID, keyword_begin(), getNumArgs()); |
472 | 633k | } |
473 | | }; |
474 | | |
475 | | } // namespace clang. |
476 | | |
477 | 7 | bool Selector::isKeywordSelector(ArrayRef<StringRef> Names) const { |
478 | 7 | assert(!Names.empty() && "must have >= 1 selector slots"); |
479 | 7 | if (getNumArgs() != Names.size()) |
480 | 2 | return false; |
481 | 14 | for (unsigned I = 0, E = Names.size(); 5 I != E; ++I9 ) { |
482 | 11 | if (getNameForSlot(I) != Names[I]) |
483 | 2 | return false; |
484 | 11 | } |
485 | 3 | return true; |
486 | 5 | } |
487 | | |
488 | 0 | bool Selector::isUnarySelector(StringRef Name) const { |
489 | 0 | return isUnarySelector() && getNameForSlot(0) == Name; |
490 | 0 | } |
491 | | |
492 | 3.17M | unsigned Selector::getNumArgs() const { |
493 | 3.17M | unsigned IIF = getIdentifierInfoFlag(); |
494 | 3.17M | if (IIF <= ZeroArg) |
495 | 834k | return 0; |
496 | 2.34M | if (IIF == OneArg) |
497 | 1.18M | return 1; |
498 | | // We point to a MultiKeywordSelector. |
499 | 1.15M | MultiKeywordSelector *SI = getMultiKeywordSelector(); |
500 | 1.15M | return SI->getNumArgs(); |
501 | 2.34M | } |
502 | | |
503 | 2.48M | IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { |
504 | 2.48M | if (getIdentifierInfoFlag() < MultiArg) { |
505 | 1.45M | assert(argIndex == 0 && "illegal keyword index"); |
506 | 0 | return getAsIdentifierInfo(); |
507 | 1.45M | } |
508 | | |
509 | | // We point to a MultiKeywordSelector. |
510 | 1.03M | MultiKeywordSelector *SI = getMultiKeywordSelector(); |
511 | 1.03M | return SI->getIdentifierInfoForSlot(argIndex); |
512 | 2.48M | } |
513 | | |
514 | 280k | StringRef Selector::getNameForSlot(unsigned int argIndex) const { |
515 | 280k | IdentifierInfo *II = getIdentifierInfoForSlot(argIndex); |
516 | 280k | return II ? II->getName()280k : StringRef()14 ; |
517 | 280k | } |
518 | | |
519 | 27.3k | std::string MultiKeywordSelector::getName() const { |
520 | 27.3k | SmallString<256> Str; |
521 | 27.3k | llvm::raw_svector_ostream OS(Str); |
522 | 103k | for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I76.6k ) { |
523 | 76.6k | if (*I) |
524 | 76.0k | OS << (*I)->getName(); |
525 | 76.6k | OS << ':'; |
526 | 76.6k | } |
527 | | |
528 | 27.3k | return std::string(OS.str()); |
529 | 27.3k | } |
530 | | |
531 | 178k | std::string Selector::getAsString() const { |
532 | 178k | if (InfoPtr == 0) |
533 | 6 | return "<null selector>"; |
534 | | |
535 | 178k | if (getIdentifierInfoFlag() < MultiArg) { |
536 | 151k | IdentifierInfo *II = getAsIdentifierInfo(); |
537 | | |
538 | 151k | if (getNumArgs() == 0) { |
539 | 118k | assert(II && "If the number of arguments is 0 then II is guaranteed to " |
540 | 118k | "not be null."); |
541 | 0 | return std::string(II->getName()); |
542 | 118k | } |
543 | | |
544 | 32.1k | if (!II) |
545 | 190 | return ":"; |
546 | | |
547 | 31.9k | return II->getName().str() + ":"; |
548 | 32.1k | } |
549 | | |
550 | | // We have a multiple keyword selector. |
551 | 27.3k | return getMultiKeywordSelector()->getName(); |
552 | 178k | } |
553 | | |
554 | 13.1k | void Selector::print(llvm::raw_ostream &OS) const { |
555 | 13.1k | OS << getAsString(); |
556 | 13.1k | } |
557 | | |
558 | 0 | LLVM_DUMP_METHOD void Selector::dump() const { print(llvm::errs()); } |
559 | | |
560 | | /// Interpreting the given string using the normal CamelCase |
561 | | /// conventions, determine whether the given string starts with the |
562 | | /// given "word", which is assumed to end in a lowercase letter. |
563 | 114k | static bool startsWithWord(StringRef name, StringRef word) { |
564 | 114k | if (name.size() < word.size()) return false4.00k ; |
565 | 110k | return ((name.size() == word.size() || !isLowercase(name[word.size()])95.3k ) && |
566 | 110k | name.startswith(word)70.0k ); |
567 | 114k | } |
568 | | |
569 | 243k | ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) { |
570 | 243k | IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); |
571 | 243k | if (!first) return OMF_None22 ; |
572 | | |
573 | 243k | StringRef name = first->getName(); |
574 | 243k | if (sel.isUnarySelector()) { |
575 | 70.0k | if (name == "autorelease") return OMF_autorelease955 ; |
576 | 69.0k | if (name == "dealloc") return OMF_dealloc848 ; |
577 | 68.2k | if (name == "finalize") return OMF_finalize154 ; |
578 | 68.0k | if (name == "release") return OMF_release1.36k ; |
579 | 66.7k | if (name == "retain") return OMF_retain702 ; |
580 | 66.0k | if (name == "retainCount") return OMF_retainCount108 ; |
581 | 65.9k | if (name == "self") return OMF_self100 ; |
582 | 65.8k | if (name == "initialize") return OMF_initialize34 ; |
583 | 65.8k | } |
584 | | |
585 | 239k | if (name == "performSelector" || name == "performSelectorInBackground"238k || |
586 | 239k | name == "performSelectorOnMainThread"238k ) |
587 | 974 | return OMF_performSelector; |
588 | | |
589 | | // The other method families may begin with a prefix of underscores. |
590 | 238k | while (238k !name.empty() && name.front() == '_') |
591 | 233 | name = name.substr(1); |
592 | | |
593 | 238k | if (name.empty()) return OMF_None0 ; |
594 | 238k | switch (name.front()) { |
595 | 18.9k | case 'a': |
596 | 18.9k | if (startsWithWord(name, "alloc")) return OMF_alloc4.94k ; |
597 | 14.0k | break; |
598 | 15.3k | case 'c': |
599 | 15.3k | if (startsWithWord(name, "copy")) return OMF_copy1.49k ; |
600 | 13.8k | break; |
601 | 61.9k | case 'i': |
602 | 61.9k | if (startsWithWord(name, "init")) return OMF_init55.6k ; |
603 | 6.26k | break; |
604 | 7.90k | case 'm': |
605 | 7.90k | if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy978 ; |
606 | 6.93k | break; |
607 | 9.67k | case 'n': |
608 | 9.67k | if (startsWithWord(name, "new")) return OMF_new1.51k ; |
609 | 8.15k | break; |
610 | 124k | default: |
611 | 124k | break; |
612 | 238k | } |
613 | | |
614 | 173k | return OMF_None; |
615 | 238k | } |
616 | | |
617 | 554 | ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) { |
618 | 554 | IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); |
619 | 554 | if (!first) return OIT_None2 ; |
620 | | |
621 | 552 | StringRef name = first->getName(); |
622 | | |
623 | 552 | if (name.empty()) return OIT_None0 ; |
624 | 552 | switch (name.front()) { |
625 | 53 | case 'a': |
626 | 53 | if (startsWithWord(name, "array")) return OIT_Array15 ; |
627 | 38 | break; |
628 | 38 | case 'd': |
629 | 37 | if (startsWithWord(name, "default")) return OIT_ReturnsSelf2 ; |
630 | 35 | if (startsWithWord(name, "dictionary")) return OIT_Dictionary11 ; |
631 | 24 | break; |
632 | 35 | case 's': |
633 | 35 | if (startsWithWord(name, "shared")) return OIT_ReturnsSelf2 ; |
634 | 33 | if (startsWithWord(name, "standard")) return OIT_Singleton1 ; |
635 | 32 | break; |
636 | 93 | case 'i': |
637 | 93 | if (startsWithWord(name, "init")) return OIT_Init45 ; |
638 | 48 | break; |
639 | 334 | default: |
640 | 334 | break; |
641 | 552 | } |
642 | 476 | return OIT_None; |
643 | 552 | } |
644 | | |
645 | 25.3k | ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) { |
646 | 25.3k | IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); |
647 | 25.3k | if (!first) return SFF_None6 ; |
648 | | |
649 | 25.3k | StringRef name = first->getName(); |
650 | | |
651 | 25.3k | switch (name.front()) { |
652 | 5.48k | case 'a': |
653 | 5.48k | if (name == "appendFormat") return SFF_NSString1 ; |
654 | 5.47k | break; |
655 | | |
656 | 5.47k | case 'i': |
657 | 3.30k | if (name == "initWithFormat") return SFF_NSString7 ; |
658 | 3.29k | break; |
659 | | |
660 | 3.29k | case 'l': |
661 | 275 | if (name == "localizedStringWithFormat") return SFF_NSString2 ; |
662 | 273 | break; |
663 | | |
664 | 3.77k | case 's': |
665 | 3.77k | if (name == "stringByAppendingFormat" || |
666 | 3.77k | name == "stringWithFormat"3.72k ) return SFF_NSString688 ; |
667 | 3.08k | break; |
668 | 25.3k | } |
669 | 24.6k | return SFF_None; |
670 | 25.3k | } |
671 | | |
672 | | namespace { |
673 | | |
674 | | struct SelectorTableImpl { |
675 | | llvm::FoldingSet<MultiKeywordSelector> Table; |
676 | | llvm::BumpPtrAllocator Allocator; |
677 | | }; |
678 | | |
679 | | } // namespace |
680 | | |
681 | 417k | static SelectorTableImpl &getSelectorTableImpl(void *P) { |
682 | 417k | return *static_cast<SelectorTableImpl*>(P); |
683 | 417k | } |
684 | | |
685 | | SmallString<64> |
686 | 357k | SelectorTable::constructSetterName(StringRef Name) { |
687 | 357k | SmallString<64> SetterName("set"); |
688 | 357k | SetterName += Name; |
689 | 357k | SetterName[3] = toUppercase(SetterName[3]); |
690 | 357k | return SetterName; |
691 | 357k | } |
692 | | |
693 | | Selector |
694 | | SelectorTable::constructSetterSelector(IdentifierTable &Idents, |
695 | | SelectorTable &SelTable, |
696 | 352k | const IdentifierInfo *Name) { |
697 | 352k | IdentifierInfo *SetterName = |
698 | 352k | &Idents.get(constructSetterName(Name->getName())); |
699 | 352k | return SelTable.getUnarySelector(SetterName); |
700 | 352k | } |
701 | | |
702 | 1 | std::string SelectorTable::getPropertyNameFromSetterSelector(Selector Sel) { |
703 | 1 | StringRef Name = Sel.getNameForSlot(0); |
704 | 1 | assert(Name.startswith("set") && "invalid setter name"); |
705 | 0 | return (Twine(toLowercase(Name[3])) + Name.drop_front(4)).str(); |
706 | 1 | } |
707 | | |
708 | 1 | size_t SelectorTable::getTotalMemory() const { |
709 | 1 | SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl); |
710 | 1 | return SelTabImpl.Allocator.getTotalMemory(); |
711 | 1 | } |
712 | | |
713 | 696k | Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) { |
714 | 696k | if (nKeys < 2) |
715 | 372k | return Selector(IIV[0], nKeys); |
716 | | |
717 | 324k | SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl); |
718 | | |
719 | | // Unique selector, to guarantee there is one per name. |
720 | 324k | llvm::FoldingSetNodeID ID; |
721 | 324k | MultiKeywordSelector::Profile(ID, IIV, nKeys); |
722 | | |
723 | 324k | void *InsertPos = nullptr; |
724 | 324k | if (MultiKeywordSelector *SI = |
725 | 324k | SelTabImpl.Table.FindNodeOrInsertPos(ID, InsertPos)) |
726 | 80.2k | return Selector(SI); |
727 | | |
728 | | // MultiKeywordSelector objects are not allocated with new because they have a |
729 | | // variable size array (for parameter types) at the end of them. |
730 | 243k | unsigned Size = sizeof(MultiKeywordSelector) + nKeys*sizeof(IdentifierInfo *); |
731 | 243k | MultiKeywordSelector *SI = |
732 | 243k | (MultiKeywordSelector *)SelTabImpl.Allocator.Allocate( |
733 | 243k | Size, alignof(MultiKeywordSelector)); |
734 | 243k | new (SI) MultiKeywordSelector(nKeys, IIV); |
735 | 243k | SelTabImpl.Table.InsertNode(SI, InsertPos); |
736 | 243k | return Selector(SI); |
737 | 324k | } |
738 | | |
739 | 99.3k | SelectorTable::SelectorTable() { |
740 | 99.3k | Impl = new SelectorTableImpl(); |
741 | 99.3k | } |
742 | | |
743 | 92.9k | SelectorTable::~SelectorTable() { |
744 | 92.9k | delete &getSelectorTableImpl(Impl); |
745 | 92.9k | } |
746 | | |
747 | 3.38M | const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) { |
748 | 3.38M | switch (Operator) { |
749 | 0 | case OO_None: |
750 | 0 | case NUM_OVERLOADED_OPERATORS: |
751 | 0 | return nullptr; |
752 | | |
753 | 0 | #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ |
754 | 3.38M | case OO_##Name: return Spelling; |
755 | 3.38M | #include "clang/Basic/OperatorKinds.def"0 |
756 | 3.38M | } |
757 | | |
758 | 0 | llvm_unreachable("Invalid OverloadedOperatorKind!"); |
759 | 0 | } |
760 | | |
761 | | StringRef clang::getNullabilitySpelling(NullabilityKind kind, |
762 | 1.18k | bool isContextSensitive) { |
763 | 1.18k | switch (kind) { |
764 | 699 | case NullabilityKind::NonNull: |
765 | 699 | return isContextSensitive ? "nonnull"224 : "_Nonnull"475 ; |
766 | | |
767 | 483 | case NullabilityKind::Nullable: |
768 | 483 | return isContextSensitive ? "nullable"58 : "_Nullable"425 ; |
769 | | |
770 | 0 | case NullabilityKind::NullableResult: |
771 | 0 | assert(!isContextSensitive && |
772 | 0 | "_Nullable_result isn't supported as context-sensitive keyword"); |
773 | 0 | return "_Nullable_result"; |
774 | | |
775 | 0 | case NullabilityKind::Unspecified: |
776 | 0 | return isContextSensitive ? "null_unspecified" : "_Null_unspecified"; |
777 | 1.18k | } |
778 | 0 | llvm_unreachable("Unknown nullability kind."); |
779 | 0 | } |