1461a67faSDimitry Andric //===- PreprocessingRecord.cpp - Record of Preprocessing ------------------===//
2c0c7bca4SRoman Divacky //
322989816SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422989816SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
522989816SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c0c7bca4SRoman Divacky //
7c0c7bca4SRoman Divacky //===----------------------------------------------------------------------===//
8c0c7bca4SRoman Divacky //
9c0c7bca4SRoman Divacky // This file implements the PreprocessingRecord class, which maintains a record
10c0c7bca4SRoman Divacky // of what occurred during preprocessing, and its helpers.
11c0c7bca4SRoman Divacky //
12c0c7bca4SRoman Divacky //===----------------------------------------------------------------------===//
13461a67faSDimitry Andric
14c0c7bca4SRoman Divacky #include "clang/Lex/PreprocessingRecord.h"
15461a67faSDimitry Andric #include "clang/Basic/IdentifierTable.h"
16461a67faSDimitry Andric #include "clang/Basic/LLVM.h"
17461a67faSDimitry Andric #include "clang/Basic/SourceLocation.h"
18461a67faSDimitry Andric #include "clang/Basic/SourceManager.h"
19461a67faSDimitry Andric #include "clang/Basic/TokenKinds.h"
20c0c7bca4SRoman Divacky #include "clang/Lex/MacroInfo.h"
21c0c7bca4SRoman Divacky #include "clang/Lex/Token.h"
22461a67faSDimitry Andric #include "llvm/ADT/DenseMap.h"
23461a67faSDimitry Andric #include "llvm/ADT/StringRef.h"
24461a67faSDimitry Andric #include "llvm/ADT/iterator_range.h"
2536981b17SDimitry Andric #include "llvm/Support/Capacity.h"
26461a67faSDimitry Andric #include "llvm/Support/Casting.h"
27809500fcSDimitry Andric #include "llvm/Support/ErrorHandling.h"
28461a67faSDimitry Andric #include <algorithm>
29461a67faSDimitry Andric #include <cassert>
30461a67faSDimitry Andric #include <cstddef>
31461a67faSDimitry Andric #include <cstring>
32461a67faSDimitry Andric #include <iterator>
33e3b55780SDimitry Andric #include <optional>
34461a67faSDimitry Andric #include <utility>
35461a67faSDimitry Andric #include <vector>
36c0c7bca4SRoman Divacky
37c0c7bca4SRoman Divacky using namespace clang;
38c0c7bca4SRoman Divacky
39461a67faSDimitry Andric ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() =
40461a67faSDimitry Andric default;
41c0c7bca4SRoman Divacky
InclusionDirective(PreprocessingRecord & PPRec,InclusionKind Kind,StringRef FileName,bool InQuotes,bool ImportedModule,OptionalFileEntryRef File,SourceRange Range)42bca07a45SDimitry Andric InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
43bab175ecSDimitry Andric InclusionKind Kind, StringRef FileName,
4413cc256eSDimitry Andric bool InQuotes, bool ImportedModule,
45e3b55780SDimitry Andric OptionalFileEntryRef File,
46145449b1SDimitry Andric SourceRange Range)
47bab175ecSDimitry Andric : PreprocessingDirective(InclusionDirectiveKind, Range), InQuotes(InQuotes),
48bab175ecSDimitry Andric Kind(Kind), ImportedModule(ImportedModule), File(File) {
49bab175ecSDimitry Andric char *Memory = (char *)PPRec.Allocate(FileName.size() + 1, alignof(char));
50bca07a45SDimitry Andric memcpy(Memory, FileName.data(), FileName.size());
51bca07a45SDimitry Andric Memory[FileName.size()] = 0;
5236981b17SDimitry Andric this->FileName = StringRef(Memory, FileName.size());
53bca07a45SDimitry Andric }
54bca07a45SDimitry Andric
PreprocessingRecord(SourceManager & SM)55461a67faSDimitry Andric PreprocessingRecord::PreprocessingRecord(SourceManager &SM) : SourceMgr(SM) {}
56c0c7bca4SRoman Divacky
5748675466SDimitry Andric /// Returns a pair of [Begin, End) iterators of preprocessed entities
5856d91b49SDimitry Andric /// that source range \p Range encompasses.
595e20cdd8SDimitry Andric llvm::iterator_range<PreprocessingRecord::iterator>
getPreprocessedEntitiesInRange(SourceRange Range)6036981b17SDimitry Andric PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) {
6136981b17SDimitry Andric if (Range.isInvalid())
625e20cdd8SDimitry Andric return llvm::make_range(iterator(), iterator());
63dbe13110SDimitry Andric
64dbe13110SDimitry Andric if (CachedRangeQuery.Range == Range) {
655e20cdd8SDimitry Andric return llvm::make_range(iterator(this, CachedRangeQuery.Result.first),
66dbe13110SDimitry Andric iterator(this, CachedRangeQuery.Result.second));
67dbe13110SDimitry Andric }
68dbe13110SDimitry Andric
6913cc256eSDimitry Andric std::pair<int, int> Res = getPreprocessedEntitiesInRangeSlow(Range);
70dbe13110SDimitry Andric
71dbe13110SDimitry Andric CachedRangeQuery.Range = Range;
72dbe13110SDimitry Andric CachedRangeQuery.Result = Res;
73dbe13110SDimitry Andric
745e20cdd8SDimitry Andric return llvm::make_range(iterator(this, Res.first),
755e20cdd8SDimitry Andric iterator(this, Res.second));
76dbe13110SDimitry Andric }
77dbe13110SDimitry Andric
isPreprocessedEntityIfInFileID(PreprocessedEntity * PPE,FileID FID,SourceManager & SM)78dbe13110SDimitry Andric static bool isPreprocessedEntityIfInFileID(PreprocessedEntity *PPE, FileID FID,
79dbe13110SDimitry Andric SourceManager &SM) {
8045b53394SDimitry Andric assert(FID.isValid());
81dbe13110SDimitry Andric if (!PPE)
82dbe13110SDimitry Andric return false;
83dbe13110SDimitry Andric
84dbe13110SDimitry Andric SourceLocation Loc = PPE->getSourceRange().getBegin();
85dbe13110SDimitry Andric if (Loc.isInvalid())
86dbe13110SDimitry Andric return false;
87dbe13110SDimitry Andric
885e20cdd8SDimitry Andric return SM.isInFileID(SM.getFileLoc(Loc), FID);
89dbe13110SDimitry Andric }
90dbe13110SDimitry Andric
9148675466SDimitry Andric /// Returns true if the preprocessed entity that \arg PPEI iterator
92dbe13110SDimitry Andric /// points to is coming from the file \arg FID.
93dbe13110SDimitry Andric ///
94dbe13110SDimitry Andric /// Can be used to avoid implicit deserializations of preallocated
95dbe13110SDimitry Andric /// preprocessed entities if we only care about entities of a specific file
9656d91b49SDimitry Andric /// and not from files \#included in the range given at
97dbe13110SDimitry Andric /// \see getPreprocessedEntitiesInRange.
isEntityInFileID(iterator PPEI,FileID FID)98dbe13110SDimitry Andric bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
99dbe13110SDimitry Andric if (FID.isInvalid())
100dbe13110SDimitry Andric return false;
101dbe13110SDimitry Andric
1025e20cdd8SDimitry Andric int Pos = std::distance(iterator(this, 0), PPEI);
10313cc256eSDimitry Andric if (Pos < 0) {
104809500fcSDimitry Andric if (unsigned(-Pos-1) >= LoadedPreprocessedEntities.size()) {
105809500fcSDimitry Andric assert(0 && "Out-of bounds loaded preprocessed entity");
106809500fcSDimitry Andric return false;
107809500fcSDimitry Andric }
108dbe13110SDimitry Andric assert(ExternalSource && "No external source to load from");
10913cc256eSDimitry Andric unsigned LoadedIndex = LoadedPreprocessedEntities.size()+Pos;
110dbe13110SDimitry Andric if (PreprocessedEntity *PPE = LoadedPreprocessedEntities[LoadedIndex])
111dbe13110SDimitry Andric return isPreprocessedEntityIfInFileID(PPE, FID, SourceMgr);
112dbe13110SDimitry Andric
113dbe13110SDimitry Andric // See if the external source can see if the entity is in the file without
114dbe13110SDimitry Andric // deserializing it.
115e3b55780SDimitry Andric if (std::optional<bool> IsInFile =
116e3b55780SDimitry Andric ExternalSource->isPreprocessedEntityInFileID(LoadedIndex, FID))
117e3b55780SDimitry Andric return *IsInFile;
118dbe13110SDimitry Andric
119dbe13110SDimitry Andric // The external source did not provide a definite answer, go and deserialize
120dbe13110SDimitry Andric // the entity to check it.
121dbe13110SDimitry Andric return isPreprocessedEntityIfInFileID(
122dbe13110SDimitry Andric getLoadedPreprocessedEntity(LoadedIndex),
123dbe13110SDimitry Andric FID, SourceMgr);
124dbe13110SDimitry Andric }
125dbe13110SDimitry Andric
126809500fcSDimitry Andric if (unsigned(Pos) >= PreprocessedEntities.size()) {
127809500fcSDimitry Andric assert(0 && "Out-of bounds local preprocessed entity");
128809500fcSDimitry Andric return false;
129809500fcSDimitry Andric }
13013cc256eSDimitry Andric return isPreprocessedEntityIfInFileID(PreprocessedEntities[Pos],
131dbe13110SDimitry Andric FID, SourceMgr);
132dbe13110SDimitry Andric }
133dbe13110SDimitry Andric
13448675466SDimitry Andric /// Returns a pair of [Begin, End) iterators of preprocessed entities
135dbe13110SDimitry Andric /// that source range \arg R encompasses.
13613cc256eSDimitry Andric std::pair<int, int>
getPreprocessedEntitiesInRangeSlow(SourceRange Range)137dbe13110SDimitry Andric PreprocessingRecord::getPreprocessedEntitiesInRangeSlow(SourceRange Range) {
138dbe13110SDimitry Andric assert(Range.isValid());
13936981b17SDimitry Andric assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
140c0c7bca4SRoman Divacky
14136981b17SDimitry Andric std::pair<unsigned, unsigned>
14236981b17SDimitry Andric Local = findLocalPreprocessedEntitiesInRange(Range);
14336981b17SDimitry Andric
14436981b17SDimitry Andric // Check if range spans local entities.
14536981b17SDimitry Andric if (!ExternalSource || SourceMgr.isLocalSourceLocation(Range.getBegin()))
146dbe13110SDimitry Andric return std::make_pair(Local.first, Local.second);
14736981b17SDimitry Andric
14836981b17SDimitry Andric std::pair<unsigned, unsigned>
14936981b17SDimitry Andric Loaded = ExternalSource->findPreprocessedEntitiesInRange(Range);
15036981b17SDimitry Andric
15136981b17SDimitry Andric // Check if range spans local entities.
15236981b17SDimitry Andric if (Loaded.first == Loaded.second)
153dbe13110SDimitry Andric return std::make_pair(Local.first, Local.second);
15436981b17SDimitry Andric
15536981b17SDimitry Andric unsigned TotalLoaded = LoadedPreprocessedEntities.size();
15636981b17SDimitry Andric
15736981b17SDimitry Andric // Check if range spans loaded entities.
15836981b17SDimitry Andric if (Local.first == Local.second)
159dbe13110SDimitry Andric return std::make_pair(int(Loaded.first)-TotalLoaded,
160dbe13110SDimitry Andric int(Loaded.second)-TotalLoaded);
16136981b17SDimitry Andric
16236981b17SDimitry Andric // Range spands loaded and local entities.
163dbe13110SDimitry Andric return std::make_pair(int(Loaded.first)-TotalLoaded, Local.second);
164c0c7bca4SRoman Divacky }
165c0c7bca4SRoman Divacky
16636981b17SDimitry Andric std::pair<unsigned, unsigned>
findLocalPreprocessedEntitiesInRange(SourceRange Range) const16736981b17SDimitry Andric PreprocessingRecord::findLocalPreprocessedEntitiesInRange(
16836981b17SDimitry Andric SourceRange Range) const {
16936981b17SDimitry Andric if (Range.isInvalid())
17036981b17SDimitry Andric return std::make_pair(0,0);
17136981b17SDimitry Andric assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
172c0c7bca4SRoman Divacky
17336981b17SDimitry Andric unsigned Begin = findBeginLocalPreprocessedEntity(Range.getBegin());
17436981b17SDimitry Andric unsigned End = findEndLocalPreprocessedEntity(Range.getEnd());
17536981b17SDimitry Andric return std::make_pair(Begin, End);
176c0c7bca4SRoman Divacky }
177c0c7bca4SRoman Divacky
17836981b17SDimitry Andric namespace {
179c0c7bca4SRoman Divacky
18036981b17SDimitry Andric template <SourceLocation (SourceRange::*getRangeLoc)() const>
18136981b17SDimitry Andric struct PPEntityComp {
18236981b17SDimitry Andric const SourceManager &SM;
18336981b17SDimitry Andric
PPEntityComp__anon41257eea0111::PPEntityComp18436981b17SDimitry Andric explicit PPEntityComp(const SourceManager &SM) : SM(SM) {}
18536981b17SDimitry Andric
operator ()__anon41257eea0111::PPEntityComp18636981b17SDimitry Andric bool operator()(PreprocessedEntity *L, PreprocessedEntity *R) const {
18736981b17SDimitry Andric SourceLocation LHS = getLoc(L);
18836981b17SDimitry Andric SourceLocation RHS = getLoc(R);
18936981b17SDimitry Andric return SM.isBeforeInTranslationUnit(LHS, RHS);
190c0c7bca4SRoman Divacky }
191c0c7bca4SRoman Divacky
operator ()__anon41257eea0111::PPEntityComp19236981b17SDimitry Andric bool operator()(PreprocessedEntity *L, SourceLocation RHS) const {
19336981b17SDimitry Andric SourceLocation LHS = getLoc(L);
19436981b17SDimitry Andric return SM.isBeforeInTranslationUnit(LHS, RHS);
19536981b17SDimitry Andric }
196c0c7bca4SRoman Divacky
operator ()__anon41257eea0111::PPEntityComp19736981b17SDimitry Andric bool operator()(SourceLocation LHS, PreprocessedEntity *R) const {
19836981b17SDimitry Andric SourceLocation RHS = getLoc(R);
19936981b17SDimitry Andric return SM.isBeforeInTranslationUnit(LHS, RHS);
20036981b17SDimitry Andric }
20136981b17SDimitry Andric
getLoc__anon41257eea0111::PPEntityComp20236981b17SDimitry Andric SourceLocation getLoc(PreprocessedEntity *PPE) const {
20336981b17SDimitry Andric SourceRange Range = PPE->getSourceRange();
20436981b17SDimitry Andric return (Range.*getRangeLoc)();
20536981b17SDimitry Andric }
20636981b17SDimitry Andric };
20736981b17SDimitry Andric
208461a67faSDimitry Andric } // namespace
20936981b17SDimitry Andric
findBeginLocalPreprocessedEntity(SourceLocation Loc) const21036981b17SDimitry Andric unsigned PreprocessingRecord::findBeginLocalPreprocessedEntity(
21136981b17SDimitry Andric SourceLocation Loc) const {
21236981b17SDimitry Andric if (SourceMgr.isLoadedSourceLocation(Loc))
21336981b17SDimitry Andric return 0;
21436981b17SDimitry Andric
21536981b17SDimitry Andric size_t Count = PreprocessedEntities.size();
21636981b17SDimitry Andric size_t Half;
21736981b17SDimitry Andric std::vector<PreprocessedEntity *>::const_iterator
21836981b17SDimitry Andric First = PreprocessedEntities.begin();
21936981b17SDimitry Andric std::vector<PreprocessedEntity *>::const_iterator I;
22036981b17SDimitry Andric
22136981b17SDimitry Andric // Do a binary search manually instead of using std::lower_bound because
22236981b17SDimitry Andric // The end locations of entities may be unordered (when a macro expansion
22336981b17SDimitry Andric // is inside another macro argument), but for this case it is not important
22436981b17SDimitry Andric // whether we get the first macro expansion or its containing macro.
22536981b17SDimitry Andric while (Count > 0) {
22636981b17SDimitry Andric Half = Count/2;
22736981b17SDimitry Andric I = First;
22836981b17SDimitry Andric std::advance(I, Half);
22936981b17SDimitry Andric if (SourceMgr.isBeforeInTranslationUnit((*I)->getSourceRange().getEnd(),
23036981b17SDimitry Andric Loc)){
23136981b17SDimitry Andric First = I;
23236981b17SDimitry Andric ++First;
23336981b17SDimitry Andric Count = Count - Half - 1;
23436981b17SDimitry Andric } else
23536981b17SDimitry Andric Count = Half;
23636981b17SDimitry Andric }
23736981b17SDimitry Andric
23836981b17SDimitry Andric return First - PreprocessedEntities.begin();
23936981b17SDimitry Andric }
24036981b17SDimitry Andric
24122989816SDimitry Andric unsigned
findEndLocalPreprocessedEntity(SourceLocation Loc) const24222989816SDimitry Andric PreprocessingRecord::findEndLocalPreprocessedEntity(SourceLocation Loc) const {
24336981b17SDimitry Andric if (SourceMgr.isLoadedSourceLocation(Loc))
24436981b17SDimitry Andric return 0;
24536981b17SDimitry Andric
24622989816SDimitry Andric auto I = llvm::upper_bound(PreprocessedEntities, Loc,
24736981b17SDimitry Andric PPEntityComp<&SourceRange::getBegin>(SourceMgr));
24836981b17SDimitry Andric return I - PreprocessedEntities.begin();
249c0c7bca4SRoman Divacky }
250c0c7bca4SRoman Divacky
251dbe13110SDimitry Andric PreprocessingRecord::PPEntityID
addPreprocessedEntity(PreprocessedEntity * Entity)252dbe13110SDimitry Andric PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
25336981b17SDimitry Andric assert(Entity);
25436981b17SDimitry Andric SourceLocation BeginLoc = Entity->getSourceRange().getBegin();
25536981b17SDimitry Andric
2565e20cdd8SDimitry Andric if (isa<MacroDefinitionRecord>(Entity)) {
257dbe13110SDimitry Andric assert((PreprocessedEntities.empty() ||
2585e20cdd8SDimitry Andric !SourceMgr.isBeforeInTranslationUnit(
2595e20cdd8SDimitry Andric BeginLoc,
260dbe13110SDimitry Andric PreprocessedEntities.back()->getSourceRange().getBegin())) &&
261809500fcSDimitry Andric "a macro definition was encountered out-of-order");
262dbe13110SDimitry Andric PreprocessedEntities.push_back(Entity);
263dbe13110SDimitry Andric return getPPEntityID(PreprocessedEntities.size()-1, /*isLoaded=*/false);
264dbe13110SDimitry Andric }
265dbe13110SDimitry Andric
26636981b17SDimitry Andric // Check normal case, this entity begin location is after the previous one.
26736981b17SDimitry Andric if (PreprocessedEntities.empty() ||
26836981b17SDimitry Andric !SourceMgr.isBeforeInTranslationUnit(BeginLoc,
26936981b17SDimitry Andric PreprocessedEntities.back()->getSourceRange().getBegin())) {
270c0c7bca4SRoman Divacky PreprocessedEntities.push_back(Entity);
271dbe13110SDimitry Andric return getPPEntityID(PreprocessedEntities.size()-1, /*isLoaded=*/false);
27236981b17SDimitry Andric }
27336981b17SDimitry Andric
274dbe13110SDimitry Andric // The entity's location is not after the previous one; this can happen with
275dbe13110SDimitry Andric // include directives that form the filename using macros, e.g:
276809500fcSDimitry Andric // "#include MACRO(STUFF)"
277809500fcSDimitry Andric // or with macro expansions inside macro arguments where the arguments are
278809500fcSDimitry Andric // not expanded in the same order as listed, e.g:
279809500fcSDimitry Andric // \code
280809500fcSDimitry Andric // #define M1 1
281809500fcSDimitry Andric // #define M2 2
282809500fcSDimitry Andric // #define FM(x,y) y x
283809500fcSDimitry Andric // FM(M1, M2)
284809500fcSDimitry Andric // \endcode
285dbe13110SDimitry Andric
286461a67faSDimitry Andric using pp_iter = std::vector<PreprocessedEntity *>::iterator;
287dbe13110SDimitry Andric
288dbe13110SDimitry Andric // Usually there are few macro expansions when defining the filename, do a
289dbe13110SDimitry Andric // linear search for a few entities.
290dbe13110SDimitry Andric unsigned count = 0;
291dbe13110SDimitry Andric for (pp_iter RI = PreprocessedEntities.end(),
292dbe13110SDimitry Andric Begin = PreprocessedEntities.begin();
293dbe13110SDimitry Andric RI != Begin && count < 4; --RI, ++count) {
294dbe13110SDimitry Andric pp_iter I = RI;
29536981b17SDimitry Andric --I;
29636981b17SDimitry Andric if (!SourceMgr.isBeforeInTranslationUnit(BeginLoc,
29736981b17SDimitry Andric (*I)->getSourceRange().getBegin())) {
298dbe13110SDimitry Andric pp_iter insertI = PreprocessedEntities.insert(RI, Entity);
299dbe13110SDimitry Andric return getPPEntityID(insertI - PreprocessedEntities.begin(),
300dbe13110SDimitry Andric /*isLoaded=*/false);
30136981b17SDimitry Andric }
30236981b17SDimitry Andric }
303dbe13110SDimitry Andric
304dbe13110SDimitry Andric // Linear search unsuccessful. Do a binary search.
30522989816SDimitry Andric pp_iter I =
30622989816SDimitry Andric llvm::upper_bound(PreprocessedEntities, BeginLoc,
307dbe13110SDimitry Andric PPEntityComp<&SourceRange::getBegin>(SourceMgr));
308dbe13110SDimitry Andric pp_iter insertI = PreprocessedEntities.insert(I, Entity);
309dbe13110SDimitry Andric return getPPEntityID(insertI - PreprocessedEntities.begin(),
310dbe13110SDimitry Andric /*isLoaded=*/false);
311c0c7bca4SRoman Divacky }
312c0c7bca4SRoman Divacky
SetExternalSource(ExternalPreprocessingRecordSource & Source)313c0c7bca4SRoman Divacky void PreprocessingRecord::SetExternalSource(
31436981b17SDimitry Andric ExternalPreprocessingRecordSource &Source) {
315c0c7bca4SRoman Divacky assert(!ExternalSource &&
316c0c7bca4SRoman Divacky "Preprocessing record already has an external source");
317c0c7bca4SRoman Divacky ExternalSource = &Source;
318c0c7bca4SRoman Divacky }
319c0c7bca4SRoman Divacky
allocateLoadedEntities(unsigned NumEntities)32036981b17SDimitry Andric unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities) {
32136981b17SDimitry Andric unsigned Result = LoadedPreprocessedEntities.size();
32236981b17SDimitry Andric LoadedPreprocessedEntities.resize(LoadedPreprocessedEntities.size()
32336981b17SDimitry Andric + NumEntities);
32436981b17SDimitry Andric return Result;
325c0c7bca4SRoman Divacky }
326c0c7bca4SRoman Divacky
allocateSkippedRanges(unsigned NumRanges)32748675466SDimitry Andric unsigned PreprocessingRecord::allocateSkippedRanges(unsigned NumRanges) {
32848675466SDimitry Andric unsigned Result = SkippedRanges.size();
32948675466SDimitry Andric SkippedRanges.resize(SkippedRanges.size() + NumRanges);
33048675466SDimitry Andric SkippedRangesAllLoaded = false;
33148675466SDimitry Andric return Result;
33248675466SDimitry Andric }
33348675466SDimitry Andric
ensureSkippedRangesLoaded()33448675466SDimitry Andric void PreprocessingRecord::ensureSkippedRangesLoaded() {
33548675466SDimitry Andric if (SkippedRangesAllLoaded || !ExternalSource)
33648675466SDimitry Andric return;
33748675466SDimitry Andric for (unsigned Index = 0; Index != SkippedRanges.size(); ++Index) {
33848675466SDimitry Andric if (SkippedRanges[Index].isInvalid())
33948675466SDimitry Andric SkippedRanges[Index] = ExternalSource->ReadSkippedRange(Index);
34048675466SDimitry Andric }
34148675466SDimitry Andric SkippedRangesAllLoaded = true;
34248675466SDimitry Andric }
34348675466SDimitry Andric
RegisterMacroDefinition(MacroInfo * Macro,MacroDefinitionRecord * Def)344c0c7bca4SRoman Divacky void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
3455e20cdd8SDimitry Andric MacroDefinitionRecord *Def) {
346809500fcSDimitry Andric MacroDefinitions[Macro] = Def;
34736981b17SDimitry Andric }
34836981b17SDimitry Andric
34948675466SDimitry Andric /// Retrieve the preprocessed entity at the given ID.
getPreprocessedEntity(PPEntityID PPID)35036981b17SDimitry Andric PreprocessedEntity *PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID){
35113cc256eSDimitry Andric if (PPID.ID < 0) {
35213cc256eSDimitry Andric unsigned Index = -PPID.ID - 1;
35313cc256eSDimitry Andric assert(Index < LoadedPreprocessedEntities.size() &&
35436981b17SDimitry Andric "Out-of bounds loaded preprocessed entity");
35513cc256eSDimitry Andric return getLoadedPreprocessedEntity(Index);
35636981b17SDimitry Andric }
35713cc256eSDimitry Andric
35813cc256eSDimitry Andric if (PPID.ID == 0)
3599f4dbff6SDimitry Andric return nullptr;
36013cc256eSDimitry Andric unsigned Index = PPID.ID - 1;
36113cc256eSDimitry Andric assert(Index < PreprocessedEntities.size() &&
36236981b17SDimitry Andric "Out-of bounds local preprocessed entity");
36313cc256eSDimitry Andric return PreprocessedEntities[Index];
36436981b17SDimitry Andric }
36536981b17SDimitry Andric
36648675466SDimitry Andric /// Retrieve the loaded preprocessed entity at the given index.
36736981b17SDimitry Andric PreprocessedEntity *
getLoadedPreprocessedEntity(unsigned Index)36836981b17SDimitry Andric PreprocessingRecord::getLoadedPreprocessedEntity(unsigned Index) {
36936981b17SDimitry Andric assert(Index < LoadedPreprocessedEntities.size() &&
37036981b17SDimitry Andric "Out-of bounds loaded preprocessed entity");
37136981b17SDimitry Andric assert(ExternalSource && "No external source to load from");
37236981b17SDimitry Andric PreprocessedEntity *&Entity = LoadedPreprocessedEntities[Index];
37336981b17SDimitry Andric if (!Entity) {
37436981b17SDimitry Andric Entity = ExternalSource->ReadPreprocessedEntity(Index);
37536981b17SDimitry Andric if (!Entity) // Failed to load.
37636981b17SDimitry Andric Entity = new (*this)
37736981b17SDimitry Andric PreprocessedEntity(PreprocessedEntity::InvalidKind, SourceRange());
37836981b17SDimitry Andric }
37936981b17SDimitry Andric return Entity;
380c0c7bca4SRoman Divacky }
381c0c7bca4SRoman Divacky
3825e20cdd8SDimitry Andric MacroDefinitionRecord *
findMacroDefinition(const MacroInfo * MI)3835e20cdd8SDimitry Andric PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
3847fa27ce4SDimitry Andric return MacroDefinitions.lookup(MI);
385c0c7bca4SRoman Divacky }
386c0c7bca4SRoman Divacky
addMacroExpansion(const Token & Id,const MacroInfo * MI,SourceRange Range)387809500fcSDimitry Andric void PreprocessingRecord::addMacroExpansion(const Token &Id,
388809500fcSDimitry Andric const MacroInfo *MI,
38936981b17SDimitry Andric SourceRange Range) {
390dbe13110SDimitry Andric // We don't record nested macro expansions.
391dbe13110SDimitry Andric if (Id.getLocation().isMacroID())
39229cafa66SDimitry Andric return;
39329cafa66SDimitry Andric
39436981b17SDimitry Andric if (MI->isBuiltinMacro())
3955e20cdd8SDimitry Andric addPreprocessedEntity(new (*this)
3965e20cdd8SDimitry Andric MacroExpansion(Id.getIdentifierInfo(), Range));
3975e20cdd8SDimitry Andric else if (MacroDefinitionRecord *Def = findMacroDefinition(MI))
3985e20cdd8SDimitry Andric addPreprocessedEntity(new (*this) MacroExpansion(Def, Range));
399c0c7bca4SRoman Divacky }
400c0c7bca4SRoman Divacky
Ifdef(SourceLocation Loc,const Token & MacroNameTok,const MacroDefinition & MD)401809500fcSDimitry Andric void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok,
4025e20cdd8SDimitry Andric const MacroDefinition &MD) {
403809500fcSDimitry Andric // This is not actually a macro expansion but record it as a macro reference.
404809500fcSDimitry Andric if (MD)
4055e20cdd8SDimitry Andric addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
406809500fcSDimitry Andric MacroNameTok.getLocation());
407809500fcSDimitry Andric }
408809500fcSDimitry Andric
Elifdef(SourceLocation Loc,const Token & MacroNameTok,const MacroDefinition & MD)409344a3780SDimitry Andric void PreprocessingRecord::Elifdef(SourceLocation Loc, const Token &MacroNameTok,
410344a3780SDimitry Andric const MacroDefinition &MD) {
411344a3780SDimitry Andric // This is not actually a macro expansion but record it as a macro reference.
412344a3780SDimitry Andric if (MD)
413344a3780SDimitry Andric addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
414344a3780SDimitry Andric MacroNameTok.getLocation());
415344a3780SDimitry Andric }
416344a3780SDimitry Andric
Ifndef(SourceLocation Loc,const Token & MacroNameTok,const MacroDefinition & MD)417809500fcSDimitry Andric void PreprocessingRecord::Ifndef(SourceLocation Loc, const Token &MacroNameTok,
4185e20cdd8SDimitry Andric const MacroDefinition &MD) {
419809500fcSDimitry Andric // This is not actually a macro expansion but record it as a macro reference.
420809500fcSDimitry Andric if (MD)
4215e20cdd8SDimitry Andric addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
422809500fcSDimitry Andric MacroNameTok.getLocation());
423809500fcSDimitry Andric }
424809500fcSDimitry Andric
Elifndef(SourceLocation Loc,const Token & MacroNameTok,const MacroDefinition & MD)425344a3780SDimitry Andric void PreprocessingRecord::Elifndef(SourceLocation Loc,
426344a3780SDimitry Andric const Token &MacroNameTok,
427344a3780SDimitry Andric const MacroDefinition &MD) {
428344a3780SDimitry Andric // This is not actually a macro expansion but record it as a macro reference.
429344a3780SDimitry Andric if (MD)
430344a3780SDimitry Andric addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
431344a3780SDimitry Andric MacroNameTok.getLocation());
432344a3780SDimitry Andric }
433344a3780SDimitry Andric
Defined(const Token & MacroNameTok,const MacroDefinition & MD,SourceRange Range)434809500fcSDimitry Andric void PreprocessingRecord::Defined(const Token &MacroNameTok,
4355e20cdd8SDimitry Andric const MacroDefinition &MD,
436bfef3995SDimitry Andric SourceRange Range) {
437809500fcSDimitry Andric // This is not actually a macro expansion but record it as a macro reference.
438809500fcSDimitry Andric if (MD)
4395e20cdd8SDimitry Andric addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
440809500fcSDimitry Andric MacroNameTok.getLocation());
441809500fcSDimitry Andric }
442809500fcSDimitry Andric
SourceRangeSkipped(SourceRange Range,SourceLocation EndifLoc)443461a67faSDimitry Andric void PreprocessingRecord::SourceRangeSkipped(SourceRange Range,
444461a67faSDimitry Andric SourceLocation EndifLoc) {
44548675466SDimitry Andric assert(Range.isValid());
446461a67faSDimitry Andric SkippedRanges.emplace_back(Range.getBegin(), EndifLoc);
4479f4dbff6SDimitry Andric }
4489f4dbff6SDimitry Andric
MacroExpands(const Token & Id,const MacroDefinition & MD,SourceRange Range,const MacroArgs * Args)4495e20cdd8SDimitry Andric void PreprocessingRecord::MacroExpands(const Token &Id,
4505e20cdd8SDimitry Andric const MacroDefinition &MD,
4516a037251SDimitry Andric SourceRange Range,
4526a037251SDimitry Andric const MacroArgs *Args) {
4535e20cdd8SDimitry Andric addMacroExpansion(Id, MD.getMacroInfo(), Range);
454809500fcSDimitry Andric }
455809500fcSDimitry Andric
MacroDefined(const Token & Id,const MacroDirective * MD)456bca07a45SDimitry Andric void PreprocessingRecord::MacroDefined(const Token &Id,
457809500fcSDimitry Andric const MacroDirective *MD) {
458809500fcSDimitry Andric const MacroInfo *MI = MD->getMacroInfo();
459c0c7bca4SRoman Divacky SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
4605e20cdd8SDimitry Andric MacroDefinitionRecord *Def =
4615e20cdd8SDimitry Andric new (*this) MacroDefinitionRecord(Id.getIdentifierInfo(), R);
462809500fcSDimitry Andric addPreprocessedEntity(Def);
463809500fcSDimitry Andric MacroDefinitions[MI] = Def;
464c0c7bca4SRoman Divacky }
465c0c7bca4SRoman Divacky
MacroUndefined(const Token & Id,const MacroDefinition & MD,const MacroDirective * Undef)466bca07a45SDimitry Andric void PreprocessingRecord::MacroUndefined(const Token &Id,
46757091882SDimitry Andric const MacroDefinition &MD,
46857091882SDimitry Andric const MacroDirective *Undef) {
4695e20cdd8SDimitry Andric MD.forAllDefinitions([&](MacroInfo *MI) { MacroDefinitions.erase(MI); });
470c0c7bca4SRoman Divacky }
471c0c7bca4SRoman Divacky
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,OptionalFileEntryRef File,StringRef SearchPath,StringRef RelativePath,const Module * SuggestedModule,bool ModuleImported,SrcMgr::CharacteristicKind FileType)47201af97d3SDimitry Andric void PreprocessingRecord::InclusionDirective(
473e3b55780SDimitry Andric SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
474e3b55780SDimitry Andric bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
475ac9a064cSDimitry Andric StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
476ac9a064cSDimitry Andric bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
477bca07a45SDimitry Andric InclusionDirective::InclusionKind Kind = InclusionDirective::Include;
478bca07a45SDimitry Andric
479bca07a45SDimitry Andric switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
480bca07a45SDimitry Andric case tok::pp_include:
481bca07a45SDimitry Andric Kind = InclusionDirective::Include;
482bca07a45SDimitry Andric break;
483bca07a45SDimitry Andric
484bca07a45SDimitry Andric case tok::pp_import:
485bca07a45SDimitry Andric Kind = InclusionDirective::Import;
486bca07a45SDimitry Andric break;
487bca07a45SDimitry Andric
488bca07a45SDimitry Andric case tok::pp_include_next:
489bca07a45SDimitry Andric Kind = InclusionDirective::IncludeNext;
490bca07a45SDimitry Andric break;
491bca07a45SDimitry Andric
492bca07a45SDimitry Andric case tok::pp___include_macros:
493bca07a45SDimitry Andric Kind = InclusionDirective::IncludeMacros;
494bca07a45SDimitry Andric break;
495bca07a45SDimitry Andric
496bca07a45SDimitry Andric default:
497bca07a45SDimitry Andric llvm_unreachable("Unknown include directive kind");
498bca07a45SDimitry Andric }
499bca07a45SDimitry Andric
50013cc256eSDimitry Andric SourceLocation EndLoc;
50113cc256eSDimitry Andric if (!IsAngled) {
50213cc256eSDimitry Andric EndLoc = FilenameRange.getBegin();
50313cc256eSDimitry Andric } else {
50413cc256eSDimitry Andric EndLoc = FilenameRange.getEnd();
50513cc256eSDimitry Andric if (FilenameRange.isCharRange())
50613cc256eSDimitry Andric EndLoc = EndLoc.getLocWithOffset(-1); // the InclusionDirective expects
50713cc256eSDimitry Andric // a token range.
50813cc256eSDimitry Andric }
509ac9a064cSDimitry Andric clang::InclusionDirective *ID = new (*this) clang::InclusionDirective(
510ac9a064cSDimitry Andric *this, Kind, FileName, !IsAngled, ModuleImported, File,
511461a67faSDimitry Andric SourceRange(HashLoc, EndLoc));
51236981b17SDimitry Andric addPreprocessedEntity(ID);
51336981b17SDimitry Andric }
51436981b17SDimitry Andric
getTotalMemory() const51536981b17SDimitry Andric size_t PreprocessingRecord::getTotalMemory() const {
51636981b17SDimitry Andric return BumpAlloc.getTotalMemory()
51736981b17SDimitry Andric + llvm::capacity_in_bytes(MacroDefinitions)
51836981b17SDimitry Andric + llvm::capacity_in_bytes(PreprocessedEntities)
51948675466SDimitry Andric + llvm::capacity_in_bytes(LoadedPreprocessedEntities)
52048675466SDimitry Andric + llvm::capacity_in_bytes(SkippedRanges);
521bca07a45SDimitry Andric }
522