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