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