1 //===- PreprocessingRecord.cpp - Record of Preprocessing ------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the PreprocessingRecord class, which maintains a record
10 // of what occurred during preprocessing, and its helpers.
12 //===----------------------------------------------------------------------===//
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/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"
37 using namespace clang
;
39 ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() =
42 InclusionDirective::InclusionDirective(PreprocessingRecord
&PPRec
,
43 InclusionKind Kind
, StringRef FileName
,
44 bool InQuotes
, bool ImportedModule
,
45 OptionalFileEntryRef File
,
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());
55 PreprocessingRecord::PreprocessingRecord(SourceManager
&SM
) : SourceMgr(SM
) {}
57 /// Returns a pair of [Begin, End) iterators of preprocessed entities
58 /// that source range \p Range encompasses.
59 llvm::iterator_range
<PreprocessingRecord::iterator
>
60 PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range
) {
61 if (Range
.isInvalid())
62 return llvm::make_range(iterator(), iterator());
64 if (CachedRangeQuery
.Range
== Range
) {
65 return llvm::make_range(iterator(this, CachedRangeQuery
.Result
.first
),
66 iterator(this, CachedRangeQuery
.Result
.second
));
69 std::pair
<int, int> Res
= getPreprocessedEntitiesInRangeSlow(Range
);
71 CachedRangeQuery
.Range
= Range
;
72 CachedRangeQuery
.Result
= Res
;
74 return llvm::make_range(iterator(this, Res
.first
),
75 iterator(this, Res
.second
));
78 static bool isPreprocessedEntityIfInFileID(PreprocessedEntity
*PPE
, FileID FID
,
80 assert(FID
.isValid());
84 SourceLocation Loc
= PPE
->getSourceRange().getBegin();
88 return SM
.isInFileID(SM
.getFileLoc(Loc
), FID
);
91 /// Returns true if the preprocessed entity that \arg PPEI iterator
92 /// points to is coming from the file \arg FID.
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.
98 bool PreprocessingRecord::isEntityInFileID(iterator PPEI
, FileID FID
) {
102 int Pos
= std::distance(iterator(this, 0), PPEI
);
104 if (unsigned(-Pos
-1) >= LoadedPreprocessedEntities
.size()) {
105 assert(0 && "Out-of bounds loaded preprocessed entity");
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
);
113 // See if the external source can see if the entity is in the file without
115 if (std::optional
<bool> IsInFile
=
116 ExternalSource
->isPreprocessedEntityInFileID(LoadedIndex
, FID
))
119 // The external source did not provide a definite answer, go and deserialize
120 // the entity to check it.
121 return isPreprocessedEntityIfInFileID(
122 getLoadedPreprocessedEntity(LoadedIndex
),
126 if (unsigned(Pos
) >= PreprocessedEntities
.size()) {
127 assert(0 && "Out-of bounds local preprocessed entity");
130 return isPreprocessedEntityIfInFileID(PreprocessedEntities
[Pos
],
134 /// Returns a pair of [Begin, End) iterators of preprocessed entities
135 /// that source range \arg R encompasses.
137 PreprocessingRecord::getPreprocessedEntitiesInRangeSlow(SourceRange Range
) {
138 assert(Range
.isValid());
139 assert(!SourceMgr
.isBeforeInTranslationUnit(Range
.getEnd(),Range
.getBegin()));
141 std::pair
<unsigned, unsigned>
142 Local
= findLocalPreprocessedEntitiesInRange(Range
);
144 // Check if range spans local entities.
145 if (!ExternalSource
|| SourceMgr
.isLocalSourceLocation(Range
.getBegin()))
146 return std::make_pair(Local
.first
, Local
.second
);
148 std::pair
<unsigned, unsigned>
149 Loaded
= ExternalSource
->findPreprocessedEntitiesInRange(Range
);
151 // Check if range spans local entities.
152 if (Loaded
.first
== Loaded
.second
)
153 return std::make_pair(Local
.first
, Local
.second
);
155 unsigned TotalLoaded
= LoadedPreprocessedEntities
.size();
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
);
162 // Range spands loaded and local entities.
163 return std::make_pair(int(Loaded
.first
)-TotalLoaded
, Local
.second
);
166 std::pair
<unsigned, unsigned>
167 PreprocessingRecord::findLocalPreprocessedEntitiesInRange(
168 SourceRange Range
) const {
169 if (Range
.isInvalid())
170 return std::make_pair(0,0);
171 assert(!SourceMgr
.isBeforeInTranslationUnit(Range
.getEnd(),Range
.getBegin()));
173 unsigned Begin
= findBeginLocalPreprocessedEntity(Range
.getBegin());
174 unsigned End
= findEndLocalPreprocessedEntity(Range
.getEnd());
175 return std::make_pair(Begin
, End
);
180 template <SourceLocation (SourceRange::*getRangeLoc
)() const>
181 struct PPEntityComp
{
182 const SourceManager
&SM
;
184 explicit PPEntityComp(const SourceManager
&SM
) : SM(SM
) {}
186 bool operator()(PreprocessedEntity
*L
, PreprocessedEntity
*R
) const {
187 SourceLocation LHS
= getLoc(L
);
188 SourceLocation RHS
= getLoc(R
);
189 return SM
.isBeforeInTranslationUnit(LHS
, RHS
);
192 bool operator()(PreprocessedEntity
*L
, SourceLocation RHS
) const {
193 SourceLocation LHS
= getLoc(L
);
194 return SM
.isBeforeInTranslationUnit(LHS
, RHS
);
197 bool operator()(SourceLocation LHS
, PreprocessedEntity
*R
) const {
198 SourceLocation RHS
= getLoc(R
);
199 return SM
.isBeforeInTranslationUnit(LHS
, RHS
);
202 SourceLocation
getLoc(PreprocessedEntity
*PPE
) const {
203 SourceRange Range
= PPE
->getSourceRange();
204 return (Range
.*getRangeLoc
)();
210 unsigned PreprocessingRecord::findBeginLocalPreprocessedEntity(
211 SourceLocation Loc
) const {
212 if (SourceMgr
.isLoadedSourceLocation(Loc
))
215 size_t Count
= PreprocessedEntities
.size();
217 std::vector
<PreprocessedEntity
*>::const_iterator
218 First
= PreprocessedEntities
.begin();
219 std::vector
<PreprocessedEntity
*>::const_iterator I
;
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.
228 std::advance(I
, Half
);
229 if (SourceMgr
.isBeforeInTranslationUnit((*I
)->getSourceRange().getEnd(),
233 Count
= Count
- Half
- 1;
238 return First
- PreprocessedEntities
.begin();
242 PreprocessingRecord::findEndLocalPreprocessedEntity(SourceLocation Loc
) const {
243 if (SourceMgr
.isLoadedSourceLocation(Loc
))
246 auto I
= llvm::upper_bound(PreprocessedEntities
, Loc
,
247 PPEntityComp
<&SourceRange::getBegin
>(SourceMgr
));
248 return I
- PreprocessedEntities
.begin();
251 PreprocessingRecord::PPEntityID
252 PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity
*Entity
) {
254 SourceLocation BeginLoc
= Entity
->getSourceRange().getBegin();
256 if (isa
<MacroDefinitionRecord
>(Entity
)) {
257 assert((PreprocessedEntities
.empty() ||
258 !SourceMgr
.isBeforeInTranslationUnit(
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);
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);
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:
282 // #define FM(x,y) y x
286 using pp_iter
= std::vector
<PreprocessedEntity
*>::iterator
;
288 // Usually there are few macro expansions when defining the filename, do a
289 // linear search for a few entities.
291 for (pp_iter RI
= PreprocessedEntities
.end(),
292 Begin
= PreprocessedEntities
.begin();
293 RI
!= Begin
&& count
< 4; --RI
, ++count
) {
296 if (!SourceMgr
.isBeforeInTranslationUnit(BeginLoc
,
297 (*I
)->getSourceRange().getBegin())) {
298 pp_iter insertI
= PreprocessedEntities
.insert(RI
, Entity
);
299 return getPPEntityID(insertI
- PreprocessedEntities
.begin(),
304 // Linear search unsuccessful. Do a binary search.
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(),
313 void PreprocessingRecord::SetExternalSource(
314 ExternalPreprocessingRecordSource
&Source
) {
315 assert(!ExternalSource
&&
316 "Preprocessing record already has an external source");
317 ExternalSource
= &Source
;
320 unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities
) {
321 unsigned Result
= LoadedPreprocessedEntities
.size();
322 LoadedPreprocessedEntities
.resize(LoadedPreprocessedEntities
.size()
327 unsigned PreprocessingRecord::allocateSkippedRanges(unsigned NumRanges
) {
328 unsigned Result
= SkippedRanges
.size();
329 SkippedRanges
.resize(SkippedRanges
.size() + NumRanges
);
330 SkippedRangesAllLoaded
= false;
334 void PreprocessingRecord::ensureSkippedRangesLoaded() {
335 if (SkippedRangesAllLoaded
|| !ExternalSource
)
337 for (unsigned Index
= 0; Index
!= SkippedRanges
.size(); ++Index
) {
338 if (SkippedRanges
[Index
].isInvalid())
339 SkippedRanges
[Index
] = ExternalSource
->ReadSkippedRange(Index
);
341 SkippedRangesAllLoaded
= true;
344 void PreprocessingRecord::RegisterMacroDefinition(MacroInfo
*Macro
,
345 MacroDefinitionRecord
*Def
) {
346 MacroDefinitions
[Macro
] = Def
;
349 /// Retrieve the preprocessed entity at the given ID.
350 PreprocessedEntity
*PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID
){
352 unsigned Index
= -PPID
.ID
- 1;
353 assert(Index
< LoadedPreprocessedEntities
.size() &&
354 "Out-of bounds loaded preprocessed entity");
355 return getLoadedPreprocessedEntity(Index
);
360 unsigned Index
= PPID
.ID
- 1;
361 assert(Index
< PreprocessedEntities
.size() &&
362 "Out-of bounds local preprocessed entity");
363 return PreprocessedEntities
[Index
];
366 /// Retrieve the loaded preprocessed entity at the given index.
368 PreprocessingRecord::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
];
374 Entity
= ExternalSource
->ReadPreprocessedEntity(Index
);
375 if (!Entity
) // Failed to load.
377 PreprocessedEntity(PreprocessedEntity::InvalidKind
, SourceRange());
382 MacroDefinitionRecord
*
383 PreprocessingRecord::findMacroDefinition(const MacroInfo
*MI
) {
384 return MacroDefinitions
.lookup(MI
);
387 void PreprocessingRecord::addMacroExpansion(const Token
&Id
,
390 // We don't record nested macro expansions.
391 if (Id
.getLocation().isMacroID())
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
));
401 void 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.
405 addMacroExpansion(MacroNameTok
, MD
.getMacroInfo(),
406 MacroNameTok
.getLocation());
409 void 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.
413 addMacroExpansion(MacroNameTok
, MD
.getMacroInfo(),
414 MacroNameTok
.getLocation());
417 void 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.
421 addMacroExpansion(MacroNameTok
, MD
.getMacroInfo(),
422 MacroNameTok
.getLocation());
425 void 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.
430 addMacroExpansion(MacroNameTok
, MD
.getMacroInfo(),
431 MacroNameTok
.getLocation());
434 void PreprocessingRecord::Defined(const Token
&MacroNameTok
,
435 const MacroDefinition
&MD
,
437 // This is not actually a macro expansion but record it as a macro reference.
439 addMacroExpansion(MacroNameTok
, MD
.getMacroInfo(),
440 MacroNameTok
.getLocation());
443 void PreprocessingRecord::SourceRangeSkipped(SourceRange Range
,
444 SourceLocation EndifLoc
) {
445 assert(Range
.isValid());
446 SkippedRanges
.emplace_back(Range
.getBegin(), EndifLoc
);
449 void PreprocessingRecord::MacroExpands(const Token
&Id
,
450 const MacroDefinition
&MD
,
452 const MacroArgs
*Args
) {
453 addMacroExpansion(Id
, MD
.getMacroInfo(), Range
);
456 void PreprocessingRecord::MacroDefined(const Token
&Id
,
457 const MacroDirective
*MD
) {
458 const MacroInfo
*MI
= MD
->getMacroInfo();
459 SourceRange
R(MI
->getDefinitionLoc(), MI
->getDefinitionEndLoc());
460 MacroDefinitionRecord
*Def
=
461 new (*this) MacroDefinitionRecord(Id
.getIdentifierInfo(), R
);
462 addPreprocessedEntity(Def
);
463 MacroDefinitions
[MI
] = Def
;
466 void PreprocessingRecord::MacroUndefined(const Token
&Id
,
467 const MacroDefinition
&MD
,
468 const MacroDirective
*Undef
) {
469 MD
.forAllDefinitions([&](MacroInfo
*MI
) { MacroDefinitions
.erase(MI
); });
472 void PreprocessingRecord::InclusionDirective(
473 SourceLocation HashLoc
, const Token
&IncludeTok
, StringRef FileName
,
474 bool IsAngled
, CharSourceRange FilenameRange
, OptionalFileEntryRef File
,
475 StringRef SearchPath
, StringRef RelativePath
, const Module
*Imported
,
476 SrcMgr::CharacteristicKind FileType
) {
477 InclusionDirective::InclusionKind Kind
= InclusionDirective::Include
;
479 switch (IncludeTok
.getIdentifierInfo()->getPPKeywordID()) {
480 case tok::pp_include
:
481 Kind
= InclusionDirective::Include
;
485 Kind
= InclusionDirective::Import
;
488 case tok::pp_include_next
:
489 Kind
= InclusionDirective::IncludeNext
;
492 case tok::pp___include_macros
:
493 Kind
= InclusionDirective::IncludeMacros
;
497 llvm_unreachable("Unknown include directive kind");
500 SourceLocation EndLoc
;
502 EndLoc
= FilenameRange
.getBegin();
504 EndLoc
= FilenameRange
.getEnd();
505 if (FilenameRange
.isCharRange())
506 EndLoc
= EndLoc
.getLocWithOffset(-1); // the InclusionDirective expects
509 clang::InclusionDirective
*ID
=
510 new (*this) clang::InclusionDirective(*this, Kind
, FileName
, !IsAngled
,
511 (bool)Imported
, File
,
512 SourceRange(HashLoc
, EndLoc
));
513 addPreprocessedEntity(ID
);
516 size_t PreprocessingRecord::getTotalMemory() const {
517 return BumpAlloc
.getTotalMemory()
518 + llvm::capacity_in_bytes(MacroDefinitions
)
519 + llvm::capacity_in_bytes(PreprocessedEntities
)
520 + llvm::capacity_in_bytes(LoadedPreprocessedEntities
)
521 + llvm::capacity_in_bytes(SkippedRanges
);