1 | //===- PreprocessingRecord.cpp - Record of Preprocessing ------------------===// |
---|---|
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 PreprocessingRecord class, which maintains a record |
10 | // of what occurred during preprocessing, and its helpers. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "clang/Lex/PreprocessingRecord.h" |
15 | #include "clang/Basic/IdentifierTable.h" |
16 | #include "clang/Basic/LLVM.h" |
17 | #include "clang/Basic/SourceLocation.h" |
18 | #include "clang/Basic/SourceManager.h" |
19 | #include "clang/Basic/TokenKinds.h" |
20 | #include "clang/Lex/MacroInfo.h" |
21 | #include "clang/Lex/Token.h" |
22 | #include "llvm/ADT/DenseMap.h" |
23 | #include "llvm/ADT/iterator_range.h" |
24 | #include "llvm/Support/Capacity.h" |
25 | #include "llvm/Support/ErrorHandling.h" |
26 | #include <cassert> |
27 | #include <cstddef> |
28 | #include <cstring> |
29 | #include <iterator> |
30 | #include <optional> |
31 | #include <utility> |
32 | #include <vector> |
33 | |
34 | using namespace clang; |
35 | |
36 | ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() = |
37 | default; |
38 | |
39 | InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec, |
40 | InclusionKind Kind, StringRef FileName, |
41 | bool InQuotes, bool ImportedModule, |
42 | OptionalFileEntryRef File, |
43 | SourceRange Range) |
44 | : PreprocessingDirective(InclusionDirectiveKind, Range), InQuotes(InQuotes), |
45 | Kind(Kind), ImportedModule(ImportedModule), File(File) { |
46 | char *Memory = (char *)PPRec.Allocate(Size: FileName.size() + 1, Align: alignof(char)); |
47 | memcpy(dest: Memory, src: FileName.data(), n: FileName.size()); |
48 | Memory[FileName.size()] = 0; |
49 | this->FileName = StringRef(Memory, FileName.size()); |
50 | } |
51 | |
52 | PreprocessingRecord::PreprocessingRecord(SourceManager &SM) : SourceMgr(SM) {} |
53 | |
54 | /// Returns a pair of [Begin, End) iterators of preprocessed entities |
55 | /// that source range \p Range encompasses. |
56 | llvm::iterator_range<PreprocessingRecord::iterator> |
57 | PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) { |
58 | if (Range.isInvalid()) |
59 | return llvm::make_range(x: iterator(), y: iterator()); |
60 | |
61 | if (CachedRangeQuery.Range == Range) { |
62 | return llvm::make_range(x: iterator(this, CachedRangeQuery.Result.first), |
63 | y: iterator(this, CachedRangeQuery.Result.second)); |
64 | } |
65 | |
66 | std::pair<int, int> Res = getPreprocessedEntitiesInRangeSlow(R: Range); |
67 | |
68 | CachedRangeQuery.Range = Range; |
69 | CachedRangeQuery.Result = Res; |
70 | |
71 | return llvm::make_range(x: iterator(this, Res.first), |
72 | y: iterator(this, Res.second)); |
73 | } |
74 | |
75 | static bool isPreprocessedEntityIfInFileID(PreprocessedEntity *PPE, FileID FID, |
76 | SourceManager &SM) { |
77 | assert(FID.isValid()); |
78 | if (!PPE) |
79 | return false; |
80 | |
81 | SourceLocation Loc = PPE->getSourceRange().getBegin(); |
82 | if (Loc.isInvalid()) |
83 | return false; |
84 | |
85 | return SM.isInFileID(Loc: SM.getFileLoc(Loc), FID); |
86 | } |
87 | |
88 | /// Returns true if the preprocessed entity that \arg PPEI iterator |
89 | /// points to is coming from the file \arg FID. |
90 | /// |
91 | /// Can be used to avoid implicit deserializations of preallocated |
92 | /// preprocessed entities if we only care about entities of a specific file |
93 | /// and not from files \#included in the range given at |
94 | /// \see getPreprocessedEntitiesInRange. |
95 | bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) { |
96 | if (FID.isInvalid()) |
97 | return false; |
98 | |
99 | int Pos = std::distance(first: iterator(this, 0), last: PPEI); |
100 | if (Pos < 0) { |
101 | if (unsigned(-Pos-1) >= LoadedPreprocessedEntities.size()) { |
102 | assert(0 && "Out-of bounds loaded preprocessed entity"); |
103 | return false; |
104 | } |
105 | assert(ExternalSource && "No external source to load from"); |
106 | unsigned LoadedIndex = LoadedPreprocessedEntities.size()+Pos; |
107 | if (PreprocessedEntity *PPE = LoadedPreprocessedEntities[LoadedIndex]) |
108 | return isPreprocessedEntityIfInFileID(PPE, FID, SM&: SourceMgr); |
109 | |
110 | // See if the external source can see if the entity is in the file without |
111 | // deserializing it. |
112 | if (std::optional<bool> IsInFile = |
113 | ExternalSource->isPreprocessedEntityInFileID(Index: LoadedIndex, FID)) |
114 | return *IsInFile; |
115 | |
116 | // The external source did not provide a definite answer, go and deserialize |
117 | // the entity to check it. |
118 | return isPreprocessedEntityIfInFileID( |
119 | PPE: getLoadedPreprocessedEntity(Index: LoadedIndex), |
120 | FID, SM&: SourceMgr); |
121 | } |
122 | |
123 | if (unsigned(Pos) >= PreprocessedEntities.size()) { |
124 | assert(0 && "Out-of bounds local preprocessed entity"); |
125 | return false; |
126 | } |
127 | return isPreprocessedEntityIfInFileID(PPE: PreprocessedEntities[Pos], |
128 | FID, SM&: SourceMgr); |
129 | } |
130 | |
131 | /// Returns a pair of [Begin, End) iterators of preprocessed entities |
132 | /// that source range \arg R encompasses. |
133 | std::pair<int, int> |
134 | PreprocessingRecord::getPreprocessedEntitiesInRangeSlow(SourceRange Range) { |
135 | assert(Range.isValid()); |
136 | assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); |
137 | |
138 | std::pair<unsigned, unsigned> |
139 | Local = findLocalPreprocessedEntitiesInRange(Range); |
140 | |
141 | // Check if range spans local entities. |
142 | if (!ExternalSource || SourceMgr.isLocalSourceLocation(Loc: Range.getBegin())) |
143 | return std::make_pair(x&: Local.first, y&: Local.second); |
144 | |
145 | std::pair<unsigned, unsigned> |
146 | Loaded = ExternalSource->findPreprocessedEntitiesInRange(Range); |
147 | |
148 | // Check if range spans local entities. |
149 | if (Loaded.first == Loaded.second) |
150 | return std::make_pair(x&: Local.first, y&: Local.second); |
151 | |
152 | unsigned TotalLoaded = LoadedPreprocessedEntities.size(); |
153 | |
154 | // Check if range spans loaded entities. |
155 | if (Local.first == Local.second) |
156 | return std::make_pair(x: int(Loaded.first)-TotalLoaded, |
157 | y: int(Loaded.second)-TotalLoaded); |
158 | |
159 | // Range spands loaded and local entities. |
160 | return std::make_pair(x: int(Loaded.first)-TotalLoaded, y&: Local.second); |
161 | } |
162 | |
163 | std::pair<unsigned, unsigned> |
164 | PreprocessingRecord::findLocalPreprocessedEntitiesInRange( |
165 | SourceRange Range) const { |
166 | if (Range.isInvalid()) |
167 | return std::make_pair(x: 0,y: 0); |
168 | assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); |
169 | |
170 | unsigned Begin = findBeginLocalPreprocessedEntity(Loc: Range.getBegin()); |
171 | unsigned End = findEndLocalPreprocessedEntity(Loc: Range.getEnd()); |
172 | return std::make_pair(x&: Begin, y&: End); |
173 | } |
174 | |
175 | namespace { |
176 | |
177 | template <SourceLocation (SourceRange::*getRangeLoc)() const> |
178 | struct PPEntityComp { |
179 | const SourceManager &SM; |
180 | |
181 | explicit PPEntityComp(const SourceManager &SM) : SM(SM) {} |
182 | |
183 | bool operator()(PreprocessedEntity *L, PreprocessedEntity *R) const { |
184 | SourceLocation LHS = getLoc(PPE: L); |
185 | SourceLocation RHS = getLoc(PPE: R); |
186 | return SM.isBeforeInTranslationUnit(LHS, RHS); |
187 | } |
188 | |
189 | bool operator()(PreprocessedEntity *L, SourceLocation RHS) const { |
190 | SourceLocation LHS = getLoc(PPE: L); |
191 | return SM.isBeforeInTranslationUnit(LHS, RHS); |
192 | } |
193 | |
194 | bool operator()(SourceLocation LHS, PreprocessedEntity *R) const { |
195 | SourceLocation RHS = getLoc(PPE: R); |
196 | return SM.isBeforeInTranslationUnit(LHS, RHS); |
197 | } |
198 | |
199 | SourceLocation getLoc(PreprocessedEntity *PPE) const { |
200 | SourceRange Range = PPE->getSourceRange(); |
201 | return (Range.*getRangeLoc)(); |
202 | } |
203 | }; |
204 | |
205 | } // namespace |
206 | |
207 | unsigned PreprocessingRecord::findBeginLocalPreprocessedEntity( |
208 | SourceLocation Loc) const { |
209 | if (SourceMgr.isLoadedSourceLocation(Loc)) |
210 | return 0; |
211 | |
212 | size_t Count = PreprocessedEntities.size(); |
213 | size_t Half; |
214 | std::vector<PreprocessedEntity *>::const_iterator |
215 | First = PreprocessedEntities.begin(); |
216 | std::vector<PreprocessedEntity *>::const_iterator I; |
217 | |
218 | // Do a binary search manually instead of using std::lower_bound because |
219 | // The end locations of entities may be unordered (when a macro expansion |
220 | // is inside another macro argument), but for this case it is not important |
221 | // whether we get the first macro expansion or its containing macro. |
222 | while (Count > 0) { |
223 | Half = Count/2; |
224 | I = First; |
225 | std::advance(i&: I, n: Half); |
226 | if (SourceMgr.isBeforeInTranslationUnit(LHS: (*I)->getSourceRange().getEnd(), |
227 | RHS: Loc)){ |
228 | First = I; |
229 | ++First; |
230 | Count = Count - Half - 1; |
231 | } else |
232 | Count = Half; |
233 | } |
234 | |
235 | return First - PreprocessedEntities.begin(); |
236 | } |
237 | |
238 | unsigned |
239 | PreprocessingRecord::findEndLocalPreprocessedEntity(SourceLocation Loc) const { |
240 | if (SourceMgr.isLoadedSourceLocation(Loc)) |
241 | return 0; |
242 | |
243 | auto I = llvm::upper_bound(Range: PreprocessedEntities, Value&: Loc, |
244 | C: PPEntityComp<&SourceRange::getBegin>(SourceMgr)); |
245 | return I - PreprocessedEntities.begin(); |
246 | } |
247 | |
248 | PreprocessingRecord::PPEntityID |
249 | PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) { |
250 | assert(Entity); |
251 | SourceLocation BeginLoc = Entity->getSourceRange().getBegin(); |
252 | |
253 | if (isa<MacroDefinitionRecord>(Val: Entity)) { |
254 | assert((PreprocessedEntities.empty() || |
255 | !SourceMgr.isBeforeInTranslationUnit( |
256 | BeginLoc, |
257 | PreprocessedEntities.back()->getSourceRange().getBegin())) && |
258 | "a macro definition was encountered out-of-order"); |
259 | PreprocessedEntities.push_back(x: Entity); |
260 | return getPPEntityID(Index: PreprocessedEntities.size()-1, /*isLoaded=*/false); |
261 | } |
262 | |
263 | // Check normal case, this entity begin location is after the previous one. |
264 | if (PreprocessedEntities.empty() || |
265 | !SourceMgr.isBeforeInTranslationUnit(LHS: BeginLoc, |
266 | RHS: PreprocessedEntities.back()->getSourceRange().getBegin())) { |
267 | PreprocessedEntities.push_back(x: Entity); |
268 | return getPPEntityID(Index: PreprocessedEntities.size()-1, /*isLoaded=*/false); |
269 | } |
270 | |
271 | // The entity's location is not after the previous one; this can happen with |
272 | // include directives that form the filename using macros, e.g: |
273 | // "#include MACRO(STUFF)" |
274 | // or with macro expansions inside macro arguments where the arguments are |
275 | // not expanded in the same order as listed, e.g: |
276 | // \code |
277 | // #define M1 1 |
278 | // #define M2 2 |
279 | // #define FM(x,y) y x |
280 | // FM(M1, M2) |
281 | // \endcode |
282 | |
283 | using pp_iter = std::vector<PreprocessedEntity *>::iterator; |
284 | |
285 | // Usually there are few macro expansions when defining the filename, do a |
286 | // linear search for a few entities. |
287 | unsigned count = 0; |
288 | for (pp_iter RI = PreprocessedEntities.end(), |
289 | Begin = PreprocessedEntities.begin(); |
290 | RI != Begin && count < 4; --RI, ++count) { |
291 | pp_iter I = RI; |
292 | --I; |
293 | if (!SourceMgr.isBeforeInTranslationUnit(LHS: BeginLoc, |
294 | RHS: (*I)->getSourceRange().getBegin())) { |
295 | pp_iter insertI = PreprocessedEntities.insert(position: RI, x: Entity); |
296 | return getPPEntityID(Index: insertI - PreprocessedEntities.begin(), |
297 | /*isLoaded=*/false); |
298 | } |
299 | } |
300 | |
301 | // Linear search unsuccessful. Do a binary search. |
302 | pp_iter I = |
303 | llvm::upper_bound(Range&: PreprocessedEntities, Value&: BeginLoc, |
304 | C: PPEntityComp<&SourceRange::getBegin>(SourceMgr)); |
305 | pp_iter insertI = PreprocessedEntities.insert(position: I, x: Entity); |
306 | return getPPEntityID(Index: insertI - PreprocessedEntities.begin(), |
307 | /*isLoaded=*/false); |
308 | } |
309 | |
310 | void PreprocessingRecord::SetExternalSource( |
311 | ExternalPreprocessingRecordSource &Source) { |
312 | assert(!ExternalSource && |
313 | "Preprocessing record already has an external source"); |
314 | ExternalSource = &Source; |
315 | } |
316 | |
317 | unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities) { |
318 | unsigned Result = LoadedPreprocessedEntities.size(); |
319 | LoadedPreprocessedEntities.resize(new_size: LoadedPreprocessedEntities.size() |
320 | + NumEntities); |
321 | return Result; |
322 | } |
323 | |
324 | unsigned PreprocessingRecord::allocateSkippedRanges(unsigned NumRanges) { |
325 | unsigned Result = SkippedRanges.size(); |
326 | SkippedRanges.resize(new_size: SkippedRanges.size() + NumRanges); |
327 | SkippedRangesAllLoaded = false; |
328 | return Result; |
329 | } |
330 | |
331 | void PreprocessingRecord::ensureSkippedRangesLoaded() { |
332 | if (SkippedRangesAllLoaded || !ExternalSource) |
333 | return; |
334 | for (unsigned Index = 0; Index != SkippedRanges.size(); ++Index) { |
335 | if (SkippedRanges[Index].isInvalid()) |
336 | SkippedRanges[Index] = ExternalSource->ReadSkippedRange(Index); |
337 | } |
338 | SkippedRangesAllLoaded = true; |
339 | } |
340 | |
341 | void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro, |
342 | MacroDefinitionRecord *Def) { |
343 | MacroDefinitions[Macro] = Def; |
344 | } |
345 | |
346 | /// Retrieve the preprocessed entity at the given ID. |
347 | PreprocessedEntity *PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID){ |
348 | if (PPID.ID < 0) { |
349 | unsigned Index = -PPID.ID - 1; |
350 | assert(Index < LoadedPreprocessedEntities.size() && |
351 | "Out-of bounds loaded preprocessed entity"); |
352 | return getLoadedPreprocessedEntity(Index); |
353 | } |
354 | |
355 | if (PPID.ID == 0) |
356 | return nullptr; |
357 | unsigned Index = PPID.ID - 1; |
358 | assert(Index < PreprocessedEntities.size() && |
359 | "Out-of bounds local preprocessed entity"); |
360 | return PreprocessedEntities[Index]; |
361 | } |
362 | |
363 | /// Retrieve the loaded preprocessed entity at the given index. |
364 | PreprocessedEntity * |
365 | PreprocessingRecord::getLoadedPreprocessedEntity(unsigned Index) { |
366 | assert(Index < LoadedPreprocessedEntities.size() && |
367 | "Out-of bounds loaded preprocessed entity"); |
368 | assert(ExternalSource && "No external source to load from"); |
369 | PreprocessedEntity *&Entity = LoadedPreprocessedEntities[Index]; |
370 | if (!Entity) { |
371 | Entity = ExternalSource->ReadPreprocessedEntity(Index); |
372 | if (!Entity) // Failed to load. |
373 | Entity = new (*this) |
374 | PreprocessedEntity(PreprocessedEntity::InvalidKind, SourceRange()); |
375 | } |
376 | return Entity; |
377 | } |
378 | |
379 | MacroDefinitionRecord * |
380 | PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) { |
381 | return MacroDefinitions.lookup(Val: MI); |
382 | } |
383 | |
384 | void PreprocessingRecord::addMacroExpansion(const Token &Id, |
385 | const MacroInfo *MI, |
386 | SourceRange Range) { |
387 | // We don't record nested macro expansions. |
388 | if (Id.getLocation().isMacroID()) |
389 | return; |
390 | |
391 | if (MI->isBuiltinMacro()) |
392 | addPreprocessedEntity(Entity: new (*this) |
393 | MacroExpansion(Id.getIdentifierInfo(), Range)); |
394 | else if (MacroDefinitionRecord *Def = findMacroDefinition(MI)) |
395 | addPreprocessedEntity(Entity: new (*this) MacroExpansion(Def, Range)); |
396 | } |
397 | |
398 | void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok, |
399 | const MacroDefinition &MD) { |
400 | // This is not actually a macro expansion but record it as a macro reference. |
401 | if (MD) |
402 | addMacroExpansion(Id: MacroNameTok, MI: MD.getMacroInfo(), |
403 | Range: MacroNameTok.getLocation()); |
404 | } |
405 | |
406 | void PreprocessingRecord::Elifdef(SourceLocation Loc, const Token &MacroNameTok, |
407 | const MacroDefinition &MD) { |
408 | // This is not actually a macro expansion but record it as a macro reference. |
409 | if (MD) |
410 | addMacroExpansion(Id: MacroNameTok, MI: MD.getMacroInfo(), |
411 | Range: MacroNameTok.getLocation()); |
412 | } |
413 | |
414 | void PreprocessingRecord::Ifndef(SourceLocation Loc, const Token &MacroNameTok, |
415 | const MacroDefinition &MD) { |
416 | // This is not actually a macro expansion but record it as a macro reference. |
417 | if (MD) |
418 | addMacroExpansion(Id: MacroNameTok, MI: MD.getMacroInfo(), |
419 | Range: MacroNameTok.getLocation()); |
420 | } |
421 | |
422 | void PreprocessingRecord::Elifndef(SourceLocation Loc, |
423 | const Token &MacroNameTok, |
424 | const MacroDefinition &MD) { |
425 | // This is not actually a macro expansion but record it as a macro reference. |
426 | if (MD) |
427 | addMacroExpansion(Id: MacroNameTok, MI: MD.getMacroInfo(), |
428 | Range: MacroNameTok.getLocation()); |
429 | } |
430 | |
431 | void PreprocessingRecord::Defined(const Token &MacroNameTok, |
432 | const MacroDefinition &MD, |
433 | SourceRange Range) { |
434 | // This is not actually a macro expansion but record it as a macro reference. |
435 | if (MD) |
436 | addMacroExpansion(Id: MacroNameTok, MI: MD.getMacroInfo(), |
437 | Range: MacroNameTok.getLocation()); |
438 | } |
439 | |
440 | void PreprocessingRecord::SourceRangeSkipped(SourceRange Range, |
441 | SourceLocation EndifLoc) { |
442 | assert(Range.isValid()); |
443 | SkippedRanges.emplace_back(args: Range.getBegin(), args&: EndifLoc); |
444 | } |
445 | |
446 | void PreprocessingRecord::MacroExpands(const Token &Id, |
447 | const MacroDefinition &MD, |
448 | SourceRange Range, |
449 | const MacroArgs *Args) { |
450 | addMacroExpansion(Id, MI: MD.getMacroInfo(), Range); |
451 | } |
452 | |
453 | void PreprocessingRecord::MacroDefined(const Token &Id, |
454 | const MacroDirective *MD) { |
455 | const MacroInfo *MI = MD->getMacroInfo(); |
456 | SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc()); |
457 | MacroDefinitionRecord *Def = |
458 | new (*this) MacroDefinitionRecord(Id.getIdentifierInfo(), R); |
459 | addPreprocessedEntity(Entity: Def); |
460 | MacroDefinitions[MI] = Def; |
461 | } |
462 | |
463 | void PreprocessingRecord::MacroUndefined(const Token &Id, |
464 | const MacroDefinition &MD, |
465 | const MacroDirective *Undef) { |
466 | MD.forAllDefinitions(F: [&](MacroInfo *MI) { MacroDefinitions.erase(Val: MI); }); |
467 | } |
468 | |
469 | void PreprocessingRecord::InclusionDirective( |
470 | SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, |
471 | bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, |
472 | StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule, |
473 | bool ModuleImported, SrcMgr::CharacteristicKind FileType) { |
474 | InclusionDirective::InclusionKind Kind = InclusionDirective::Include; |
475 | |
476 | switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) { |
477 | case tok::pp_include: |
478 | Kind = InclusionDirective::Include; |
479 | break; |
480 | |
481 | case tok::pp_import: |
482 | Kind = InclusionDirective::Import; |
483 | break; |
484 | |
485 | case tok::pp_include_next: |
486 | Kind = InclusionDirective::IncludeNext; |
487 | break; |
488 | |
489 | case tok::pp___include_macros: |
490 | Kind = InclusionDirective::IncludeMacros; |
491 | break; |
492 | |
493 | default: |
494 | llvm_unreachable("Unknown include directive kind"); |
495 | } |
496 | |
497 | SourceLocation EndLoc; |
498 | if (!IsAngled) { |
499 | EndLoc = FilenameRange.getBegin(); |
500 | } else { |
501 | EndLoc = FilenameRange.getEnd(); |
502 | if (FilenameRange.isCharRange()) |
503 | EndLoc = EndLoc.getLocWithOffset(Offset: -1); // the InclusionDirective expects |
504 | // a token range. |
505 | } |
506 | clang::InclusionDirective *ID = new (*this) clang::InclusionDirective( |
507 | *this, Kind, FileName, !IsAngled, ModuleImported, File, |
508 | SourceRange(HashLoc, EndLoc)); |
509 | addPreprocessedEntity(Entity: ID); |
510 | } |
511 | |
512 | size_t PreprocessingRecord::getTotalMemory() const { |
513 | return BumpAlloc.getTotalMemory() |
514 | + llvm::capacity_in_bytes(X: MacroDefinitions) |
515 | + llvm::capacity_in_bytes(x: PreprocessedEntities) |
516 | + llvm::capacity_in_bytes(x: LoadedPreprocessedEntities) |
517 | + llvm::capacity_in_bytes(x: SkippedRanges); |
518 | } |
519 |
Definitions
- ~ExternalPreprocessingRecordSource
- InclusionDirective
- PreprocessingRecord
- getPreprocessedEntitiesInRange
- isPreprocessedEntityIfInFileID
- isEntityInFileID
- getPreprocessedEntitiesInRangeSlow
- findLocalPreprocessedEntitiesInRange
- PPEntityComp
- PPEntityComp
- operator()
- operator()
- operator()
- getLoc
- findBeginLocalPreprocessedEntity
- findEndLocalPreprocessedEntity
- addPreprocessedEntity
- SetExternalSource
- allocateLoadedEntities
- allocateSkippedRanges
- ensureSkippedRangesLoaded
- RegisterMacroDefinition
- getPreprocessedEntity
- getLoadedPreprocessedEntity
- findMacroDefinition
- addMacroExpansion
- Ifdef
- Elifdef
- Ifndef
- Elifndef
- Defined
- SourceRangeSkipped
- MacroExpands
- MacroDefined
- MacroUndefined
- InclusionDirective
Improve your Profiling and Debugging skills
Find out more