clang 20.0.0git
PreprocessingRecord.cpp
Go to the documentation of this file.
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
16#include "clang/Basic/LLVM.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
34using namespace clang;
35
37 default;
38
40 InclusionKind Kind, StringRef FileName,
41 bool InQuotes, bool ImportedModule,
44 : PreprocessingDirective(InclusionDirectiveKind, Range), InQuotes(InQuotes),
45 Kind(Kind), ImportedModule(ImportedModule), File(File) {
46 char *Memory = (char *)PPRec.Allocate(FileName.size() + 1, alignof(char));
47 memcpy(Memory, FileName.data(), FileName.size());
48 Memory[FileName.size()] = 0;
49 this->FileName = StringRef(Memory, FileName.size());
50}
51
53
54/// Returns a pair of [Begin, End) iterators of preprocessed entities
55/// that source range \p Range encompasses.
56llvm::iterator_range<PreprocessingRecord::iterator>
58 if (Range.isInvalid())
59 return llvm::make_range(iterator(), iterator());
60
61 if (CachedRangeQuery.Range == Range) {
62 return llvm::make_range(iterator(this, CachedRangeQuery.Result.first),
63 iterator(this, CachedRangeQuery.Result.second));
64 }
65
66 std::pair<int, int> Res = getPreprocessedEntitiesInRangeSlow(Range);
67
68 CachedRangeQuery.Range = Range;
69 CachedRangeQuery.Result = Res;
70
71 return llvm::make_range(iterator(this, Res.first),
72 iterator(this, Res.second));
73}
74
77 assert(FID.isValid());
78 if (!PPE)
79 return false;
80
82 if (Loc.isInvalid())
83 return false;
84
85 return SM.isInFileID(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.
96 if (FID.isInvalid())
97 return false;
98
99 int Pos = std::distance(iterator(this, 0), 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, 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(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.
119 getLoadedPreprocessedEntity(LoadedIndex),
120 FID, 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(PreprocessedEntities[Pos],
128 FID, SourceMgr);
129}
130
131/// Returns a pair of [Begin, End) iterators of preprocessed entities
132/// that source range \arg R encompasses.
133std::pair<int, int>
134PreprocessingRecord::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.
143 return std::make_pair(Local.first, 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(Local.first, 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(int(Loaded.first)-TotalLoaded,
157 int(Loaded.second)-TotalLoaded);
158
159 // Range spands loaded and local entities.
160 return std::make_pair(int(Loaded.first)-TotalLoaded, Local.second);
161}
162
163std::pair<unsigned, unsigned>
164PreprocessingRecord::findLocalPreprocessedEntitiesInRange(
165 SourceRange Range) const {
166 if (Range.isInvalid())
167 return std::make_pair(0,0);
168 assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
169
170 unsigned Begin = findBeginLocalPreprocessedEntity(Range.getBegin());
171 unsigned End = findEndLocalPreprocessedEntity(Range.getEnd());
172 return std::make_pair(Begin, End);
173}
174
175namespace {
176
177template <SourceLocation (SourceRange::*getRangeLoc)() const>
178struct 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(L);
185 SourceLocation RHS = getLoc(R);
186 return SM.isBeforeInTranslationUnit(LHS, RHS);
187 }
188
189 bool operator()(PreprocessedEntity *L, SourceLocation RHS) const {
190 SourceLocation LHS = getLoc(L);
191 return SM.isBeforeInTranslationUnit(LHS, RHS);
192 }
193
194 bool operator()(SourceLocation LHS, PreprocessedEntity *R) const {
195 SourceLocation RHS = getLoc(R);
196 return SM.isBeforeInTranslationUnit(LHS, RHS);
197 }
198
199 SourceLocation getLoc(PreprocessedEntity *PPE) const {
201 return (Range.*getRangeLoc)();
202 }
203};
204
205} // namespace
206
207unsigned 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, Half);
226 if (SourceMgr.isBeforeInTranslationUnit((*I)->getSourceRange().getEnd(),
227 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
238unsigned
239PreprocessingRecord::findEndLocalPreprocessedEntity(SourceLocation Loc) const {
240 if (SourceMgr.isLoadedSourceLocation(Loc))
241 return 0;
242
243 auto I = llvm::upper_bound(PreprocessedEntities, Loc,
244 PPEntityComp<&SourceRange::getBegin>(SourceMgr));
245 return I - PreprocessedEntities.begin();
246}
247
248PreprocessingRecord::PPEntityID
250 assert(Entity);
251 SourceLocation BeginLoc = Entity->getSourceRange().getBegin();
252
253 if (isa<MacroDefinitionRecord>(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(Entity);
260 return getPPEntityID(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(BeginLoc,
266 PreprocessedEntities.back()->getSourceRange().getBegin())) {
267 PreprocessedEntities.push_back(Entity);
268 return getPPEntityID(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(BeginLoc,
294 (*I)->getSourceRange().getBegin())) {
295 pp_iter insertI = PreprocessedEntities.insert(RI, Entity);
296 return getPPEntityID(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(PreprocessedEntities, BeginLoc,
304 PPEntityComp<&SourceRange::getBegin>(SourceMgr));
305 pp_iter insertI = PreprocessedEntities.insert(I, Entity);
306 return getPPEntityID(insertI - PreprocessedEntities.begin(),
307 /*isLoaded=*/false);
308}
309
312 assert(!ExternalSource &&
313 "Preprocessing record already has an external source");
314 ExternalSource = &Source;
315}
316
317unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities) {
318 unsigned Result = LoadedPreprocessedEntities.size();
319 LoadedPreprocessedEntities.resize(LoadedPreprocessedEntities.size()
320 + NumEntities);
321 return Result;
322}
323
324unsigned PreprocessingRecord::allocateSkippedRanges(unsigned NumRanges) {
325 unsigned Result = SkippedRanges.size();
326 SkippedRanges.resize(SkippedRanges.size() + NumRanges);
327 SkippedRangesAllLoaded = false;
328 return Result;
329}
330
331void 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
341void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
343 MacroDefinitions[Macro] = Def;
344}
345
346/// Retrieve the preprocessed entity at the given ID.
347PreprocessedEntity *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.
365PreprocessingRecord::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)
375 }
376 return Entity;
377}
378
381 return MacroDefinitions.lookup(MI);
382}
383
384void PreprocessingRecord::addMacroExpansion(const Token &Id,
385 const MacroInfo *MI,
387 // We don't record nested macro expansions.
388 if (Id.getLocation().isMacroID())
389 return;
390
391 if (MI->isBuiltinMacro())
392 addPreprocessedEntity(new (*this)
393 MacroExpansion(Id.getIdentifierInfo(), Range));
394 else if (MacroDefinitionRecord *Def = findMacroDefinition(MI))
395 addPreprocessedEntity(new (*this) MacroExpansion(Def, Range));
396}
397
398void 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(MacroNameTok, MD.getMacroInfo(),
403 MacroNameTok.getLocation());
404}
405
406void 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(MacroNameTok, MD.getMacroInfo(),
411 MacroNameTok.getLocation());
412}
413
414void 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(MacroNameTok, MD.getMacroInfo(),
419 MacroNameTok.getLocation());
420}
421
422void 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(MacroNameTok, MD.getMacroInfo(),
428 MacroNameTok.getLocation());
429}
430
431void PreprocessingRecord::Defined(const Token &MacroNameTok,
432 const MacroDefinition &MD,
434 // This is not actually a macro expansion but record it as a macro reference.
435 if (MD)
436 addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
437 MacroNameTok.getLocation());
438}
439
440void PreprocessingRecord::SourceRangeSkipped(SourceRange Range,
441 SourceLocation EndifLoc) {
442 assert(Range.isValid());
443 SkippedRanges.emplace_back(Range.getBegin(), EndifLoc);
444}
445
446void PreprocessingRecord::MacroExpands(const Token &Id,
447 const MacroDefinition &MD,
449 const MacroArgs *Args) {
450 addMacroExpansion(Id, MD.getMacroInfo(), Range);
451}
452
453void PreprocessingRecord::MacroDefined(const Token &Id,
454 const MacroDirective *MD) {
455 const MacroInfo *MI = MD->getMacroInfo();
458 new (*this) MacroDefinitionRecord(Id.getIdentifierInfo(), R);
460 MacroDefinitions[MI] = Def;
461}
462
463void PreprocessingRecord::MacroUndefined(const Token &Id,
464 const MacroDefinition &MD,
465 const MacroDirective *Undef) {
466 MD.forAllDefinitions([&](MacroInfo *MI) { MacroDefinitions.erase(MI); });
467}
468
469void 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) {
475
476 switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
477 case tok::pp_include:
479 break;
480
481 case tok::pp_import:
483 break;
484
485 case tok::pp_include_next:
487 break;
488
489 case tok::pp___include_macros:
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(-1); // the InclusionDirective expects
504 // a token range.
505 }
507 *this, Kind, FileName, !IsAngled, ModuleImported, File,
508 SourceRange(HashLoc, EndLoc));
510}
511
513 return BumpAlloc.getTotalMemory()
514 + llvm::capacity_in_bytes(MacroDefinitions)
515 + llvm::capacity_in_bytes(PreprocessedEntities)
516 + llvm::capacity_in_bytes(LoadedPreprocessedEntities)
517 + llvm::capacity_in_bytes(SkippedRanges);
518}
#define SM(sm)
Definition: Cuda.cpp:84
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::MachO::FileType FileType
Definition: MachO.h:46
Defines the clang::MacroInfo and clang::MacroDirective classes.
static bool isPreprocessedEntityIfInFileID(PreprocessedEntity *PPE, FileID FID, SourceManager &SM)
uint32_t Id
Definition: SemaARM.cpp:1134
SourceRange Range
Definition: SemaObjC.cpp:758
SourceLocation Loc
Definition: SemaObjC.cpp:759
Defines the clang::SourceLocation class and associated facilities.
static bool isInvalid(LocType Loc, bool *Invalid)
Defines the SourceManager interface.
Defines the clang::TokenKind enum and support functions.
SourceLocation Begin
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
Represents a character-granular source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
An abstract class that should be subclassed by any external source of preprocessing record entries.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isValid() const
bool isInvalid() const
tok::PPKeywordKind getPPKeywordID() const
Return the preprocessor keyword ID for this identifier.
Record the location of an inclusion directive, such as an #include or #import statement.
InclusionKind
The kind of inclusion directives known to the preprocessor.
@ IncludeMacros
A Clang #__include_macros directive.
@ Import
An Objective-C #import directive.
@ IncludeNext
A GNU #include_next directive.
@ Include
An #include directive.
InclusionDirective(PreprocessingRecord &PPRec, InclusionKind Kind, StringRef FileName, bool InQuotes, bool ImportedModule, OptionalFileEntryRef File, SourceRange Range)
MacroArgs - An instance of this class captures information about the formal arguments specified to a ...
Definition: MacroArgs.h:30
Record the location of a macro definition.
A description of the current definition of a macro.
Definition: MacroInfo.h:590
MacroInfo * getMacroInfo() const
Get the MacroInfo that should be used for this definition.
Definition: MacroInfo.h:606
void forAllDefinitions(Fn F) const
Definition: MacroInfo.h:626
Encapsulates changes to the "macros namespace" (the location where the macro name became active,...
Definition: MacroInfo.h:313
const MacroInfo * getMacroInfo() const
Definition: MacroInfo.h:416
Records the location of a macro expansion.
Encapsulates the data about a macro definition (e.g.
Definition: MacroInfo.h:39
SourceLocation getDefinitionEndLoc() const
Return the location of the last token in the macro.
Definition: MacroInfo.h:131
bool isBuiltinMacro() const
Return true if this macro requires processing before expansion.
Definition: MacroInfo.h:217
SourceLocation getDefinitionLoc() const
Return the location that the macro was defined at.
Definition: MacroInfo.h:125
Describes a module or submodule.
Definition: Module.h:115
Base class that describes a preprocessed entity, which may be a preprocessor directive or macro expan...
@ InvalidKind
Indicates a problem trying to load the preprocessed entity.
SourceRange getSourceRange() const LLVM_READONLY
Retrieve the source range that covers this entire preprocessed entity.
Records the presence of a preprocessor directive.
Iteration over the preprocessed entities.
A record of the steps taken while preprocessing a source file, including the various preprocessing di...
PreprocessingRecord(SourceManager &SM)
Construct a new preprocessing record.
void * Allocate(unsigned Size, unsigned Align=8)
Allocate memory in the preprocessing record.
llvm::iterator_range< iterator > getPreprocessedEntitiesInRange(SourceRange R)
Returns a range of preprocessed entities that source range R encompasses.
MacroDefinitionRecord * findMacroDefinition(const MacroInfo *MI)
Retrieve the macro definition that corresponds to the given MacroInfo.
PPEntityID addPreprocessedEntity(PreprocessedEntity *Entity)
Add a new preprocessed entity to this record.
bool isEntityInFileID(iterator PPEI, FileID FID)
Returns true if the preprocessed entity that PPEI iterator points to is coming from the file FID.
std::pair< int, int > Result
void SetExternalSource(ExternalPreprocessingRecordSource &Source)
Set the external source for preprocessed entities.
Encodes a location in the source.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
bool isLocalSourceLocation(SourceLocation Loc) const
Returns true if Loc did not come from a PCH/Module.
bool isLoadedSourceLocation(SourceLocation Loc) const
Returns true if Loc came from a PCH/Module.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
A trivial tuple used to represent a source range.
bool isInvalid() const
SourceLocation getEnd() const
SourceLocation getBegin() const
bool isValid() const
Token - This structure provides full information about a lexed token.
Definition: Token.h:36
IdentifierInfo * getIdentifierInfo() const
Definition: Token.h:187
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
Definition: Token.h:132
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
Definition: SourceManager.h:81
The JSON file list parser is used to communicate input to InstallAPI.