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