10b57cec5SDimitry Andric //===- PreprocessingRecord.cpp - Record of Preprocessing ------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the PreprocessingRecord class, which maintains a record
100b57cec5SDimitry Andric // of what occurred during preprocessing, and its helpers.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "clang/Lex/PreprocessingRecord.h"
150b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h"
160b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
170b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h"
180b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
190b57cec5SDimitry Andric #include "clang/Basic/TokenKinds.h"
200b57cec5SDimitry Andric #include "clang/Lex/MacroInfo.h"
210b57cec5SDimitry Andric #include "clang/Lex/Token.h"
220b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
230b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
240b57cec5SDimitry Andric #include "llvm/ADT/iterator_range.h"
250b57cec5SDimitry Andric #include "llvm/Support/Capacity.h"
260b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
270b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
280b57cec5SDimitry Andric #include <algorithm>
290b57cec5SDimitry Andric #include <cassert>
300b57cec5SDimitry Andric #include <cstddef>
310b57cec5SDimitry Andric #include <cstring>
320b57cec5SDimitry Andric #include <iterator>
33bdd1243dSDimitry Andric #include <optional>
340b57cec5SDimitry Andric #include <utility>
350b57cec5SDimitry Andric #include <vector>
360b57cec5SDimitry Andric
370b57cec5SDimitry Andric using namespace clang;
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() =
400b57cec5SDimitry Andric default;
410b57cec5SDimitry Andric
InclusionDirective(PreprocessingRecord & PPRec,InclusionKind Kind,StringRef FileName,bool InQuotes,bool ImportedModule,OptionalFileEntryRef File,SourceRange Range)420b57cec5SDimitry Andric InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
430b57cec5SDimitry Andric InclusionKind Kind, StringRef FileName,
440b57cec5SDimitry Andric bool InQuotes, bool ImportedModule,
45bdd1243dSDimitry Andric OptionalFileEntryRef File,
4681ad6265SDimitry Andric SourceRange Range)
470b57cec5SDimitry Andric : PreprocessingDirective(InclusionDirectiveKind, Range), InQuotes(InQuotes),
480b57cec5SDimitry Andric Kind(Kind), ImportedModule(ImportedModule), File(File) {
490b57cec5SDimitry Andric char *Memory = (char *)PPRec.Allocate(FileName.size() + 1, alignof(char));
500b57cec5SDimitry Andric memcpy(Memory, FileName.data(), FileName.size());
510b57cec5SDimitry Andric Memory[FileName.size()] = 0;
520b57cec5SDimitry Andric this->FileName = StringRef(Memory, FileName.size());
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric
PreprocessingRecord(SourceManager & SM)550b57cec5SDimitry Andric PreprocessingRecord::PreprocessingRecord(SourceManager &SM) : SourceMgr(SM) {}
560b57cec5SDimitry Andric
570b57cec5SDimitry Andric /// Returns a pair of [Begin, End) iterators of preprocessed entities
580b57cec5SDimitry Andric /// that source range \p Range encompasses.
590b57cec5SDimitry Andric llvm::iterator_range<PreprocessingRecord::iterator>
getPreprocessedEntitiesInRange(SourceRange Range)600b57cec5SDimitry Andric PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) {
610b57cec5SDimitry Andric if (Range.isInvalid())
620b57cec5SDimitry Andric return llvm::make_range(iterator(), iterator());
630b57cec5SDimitry Andric
640b57cec5SDimitry Andric if (CachedRangeQuery.Range == Range) {
650b57cec5SDimitry Andric return llvm::make_range(iterator(this, CachedRangeQuery.Result.first),
660b57cec5SDimitry Andric iterator(this, CachedRangeQuery.Result.second));
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric std::pair<int, int> Res = getPreprocessedEntitiesInRangeSlow(Range);
700b57cec5SDimitry Andric
710b57cec5SDimitry Andric CachedRangeQuery.Range = Range;
720b57cec5SDimitry Andric CachedRangeQuery.Result = Res;
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric return llvm::make_range(iterator(this, Res.first),
750b57cec5SDimitry Andric iterator(this, Res.second));
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric
isPreprocessedEntityIfInFileID(PreprocessedEntity * PPE,FileID FID,SourceManager & SM)780b57cec5SDimitry Andric static bool isPreprocessedEntityIfInFileID(PreprocessedEntity *PPE, FileID FID,
790b57cec5SDimitry Andric SourceManager &SM) {
800b57cec5SDimitry Andric assert(FID.isValid());
810b57cec5SDimitry Andric if (!PPE)
820b57cec5SDimitry Andric return false;
830b57cec5SDimitry Andric
840b57cec5SDimitry Andric SourceLocation Loc = PPE->getSourceRange().getBegin();
850b57cec5SDimitry Andric if (Loc.isInvalid())
860b57cec5SDimitry Andric return false;
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric return SM.isInFileID(SM.getFileLoc(Loc), FID);
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric
910b57cec5SDimitry Andric /// Returns true if the preprocessed entity that \arg PPEI iterator
920b57cec5SDimitry Andric /// points to is coming from the file \arg FID.
930b57cec5SDimitry Andric ///
940b57cec5SDimitry Andric /// Can be used to avoid implicit deserializations of preallocated
950b57cec5SDimitry Andric /// preprocessed entities if we only care about entities of a specific file
960b57cec5SDimitry Andric /// and not from files \#included in the range given at
970b57cec5SDimitry Andric /// \see getPreprocessedEntitiesInRange.
isEntityInFileID(iterator PPEI,FileID FID)980b57cec5SDimitry Andric bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
990b57cec5SDimitry Andric if (FID.isInvalid())
1000b57cec5SDimitry Andric return false;
1010b57cec5SDimitry Andric
1020b57cec5SDimitry Andric int Pos = std::distance(iterator(this, 0), PPEI);
1030b57cec5SDimitry Andric if (Pos < 0) {
1040b57cec5SDimitry Andric if (unsigned(-Pos-1) >= LoadedPreprocessedEntities.size()) {
1050b57cec5SDimitry Andric assert(0 && "Out-of bounds loaded preprocessed entity");
1060b57cec5SDimitry Andric return false;
1070b57cec5SDimitry Andric }
1080b57cec5SDimitry Andric assert(ExternalSource && "No external source to load from");
1090b57cec5SDimitry Andric unsigned LoadedIndex = LoadedPreprocessedEntities.size()+Pos;
1100b57cec5SDimitry Andric if (PreprocessedEntity *PPE = LoadedPreprocessedEntities[LoadedIndex])
1110b57cec5SDimitry Andric return isPreprocessedEntityIfInFileID(PPE, FID, SourceMgr);
1120b57cec5SDimitry Andric
1130b57cec5SDimitry Andric // See if the external source can see if the entity is in the file without
1140b57cec5SDimitry Andric // deserializing it.
115bdd1243dSDimitry Andric if (std::optional<bool> IsInFile =
116bdd1243dSDimitry Andric ExternalSource->isPreprocessedEntityInFileID(LoadedIndex, FID))
117bdd1243dSDimitry Andric return *IsInFile;
1180b57cec5SDimitry Andric
1190b57cec5SDimitry Andric // The external source did not provide a definite answer, go and deserialize
1200b57cec5SDimitry Andric // the entity to check it.
1210b57cec5SDimitry Andric return isPreprocessedEntityIfInFileID(
1220b57cec5SDimitry Andric getLoadedPreprocessedEntity(LoadedIndex),
1230b57cec5SDimitry Andric FID, SourceMgr);
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric
1260b57cec5SDimitry Andric if (unsigned(Pos) >= PreprocessedEntities.size()) {
1270b57cec5SDimitry Andric assert(0 && "Out-of bounds local preprocessed entity");
1280b57cec5SDimitry Andric return false;
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric return isPreprocessedEntityIfInFileID(PreprocessedEntities[Pos],
1310b57cec5SDimitry Andric FID, SourceMgr);
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric /// Returns a pair of [Begin, End) iterators of preprocessed entities
1350b57cec5SDimitry Andric /// that source range \arg R encompasses.
1360b57cec5SDimitry Andric std::pair<int, int>
getPreprocessedEntitiesInRangeSlow(SourceRange Range)1370b57cec5SDimitry Andric PreprocessingRecord::getPreprocessedEntitiesInRangeSlow(SourceRange Range) {
1380b57cec5SDimitry Andric assert(Range.isValid());
1390b57cec5SDimitry Andric assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric std::pair<unsigned, unsigned>
1420b57cec5SDimitry Andric Local = findLocalPreprocessedEntitiesInRange(Range);
1430b57cec5SDimitry Andric
1440b57cec5SDimitry Andric // Check if range spans local entities.
1450b57cec5SDimitry Andric if (!ExternalSource || SourceMgr.isLocalSourceLocation(Range.getBegin()))
1460b57cec5SDimitry Andric return std::make_pair(Local.first, Local.second);
1470b57cec5SDimitry Andric
1480b57cec5SDimitry Andric std::pair<unsigned, unsigned>
1490b57cec5SDimitry Andric Loaded = ExternalSource->findPreprocessedEntitiesInRange(Range);
1500b57cec5SDimitry Andric
1510b57cec5SDimitry Andric // Check if range spans local entities.
1520b57cec5SDimitry Andric if (Loaded.first == Loaded.second)
1530b57cec5SDimitry Andric return std::make_pair(Local.first, Local.second);
1540b57cec5SDimitry Andric
1550b57cec5SDimitry Andric unsigned TotalLoaded = LoadedPreprocessedEntities.size();
1560b57cec5SDimitry Andric
1570b57cec5SDimitry Andric // Check if range spans loaded entities.
1580b57cec5SDimitry Andric if (Local.first == Local.second)
1590b57cec5SDimitry Andric return std::make_pair(int(Loaded.first)-TotalLoaded,
1600b57cec5SDimitry Andric int(Loaded.second)-TotalLoaded);
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric // Range spands loaded and local entities.
1630b57cec5SDimitry Andric return std::make_pair(int(Loaded.first)-TotalLoaded, Local.second);
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric
1660b57cec5SDimitry Andric std::pair<unsigned, unsigned>
findLocalPreprocessedEntitiesInRange(SourceRange Range) const1670b57cec5SDimitry Andric PreprocessingRecord::findLocalPreprocessedEntitiesInRange(
1680b57cec5SDimitry Andric SourceRange Range) const {
1690b57cec5SDimitry Andric if (Range.isInvalid())
1700b57cec5SDimitry Andric return std::make_pair(0,0);
1710b57cec5SDimitry Andric assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
1720b57cec5SDimitry Andric
1730b57cec5SDimitry Andric unsigned Begin = findBeginLocalPreprocessedEntity(Range.getBegin());
1740b57cec5SDimitry Andric unsigned End = findEndLocalPreprocessedEntity(Range.getEnd());
1750b57cec5SDimitry Andric return std::make_pair(Begin, End);
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric
1780b57cec5SDimitry Andric namespace {
1790b57cec5SDimitry Andric
1800b57cec5SDimitry Andric template <SourceLocation (SourceRange::*getRangeLoc)() const>
1810b57cec5SDimitry Andric struct PPEntityComp {
1820b57cec5SDimitry Andric const SourceManager &SM;
1830b57cec5SDimitry Andric
PPEntityComp__anondd72c81d0111::PPEntityComp1840b57cec5SDimitry Andric explicit PPEntityComp(const SourceManager &SM) : SM(SM) {}
1850b57cec5SDimitry Andric
operator ()__anondd72c81d0111::PPEntityComp1860b57cec5SDimitry Andric bool operator()(PreprocessedEntity *L, PreprocessedEntity *R) const {
1870b57cec5SDimitry Andric SourceLocation LHS = getLoc(L);
1880b57cec5SDimitry Andric SourceLocation RHS = getLoc(R);
1890b57cec5SDimitry Andric return SM.isBeforeInTranslationUnit(LHS, RHS);
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric
operator ()__anondd72c81d0111::PPEntityComp1920b57cec5SDimitry Andric bool operator()(PreprocessedEntity *L, SourceLocation RHS) const {
1930b57cec5SDimitry Andric SourceLocation LHS = getLoc(L);
1940b57cec5SDimitry Andric return SM.isBeforeInTranslationUnit(LHS, RHS);
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric
operator ()__anondd72c81d0111::PPEntityComp1970b57cec5SDimitry Andric bool operator()(SourceLocation LHS, PreprocessedEntity *R) const {
1980b57cec5SDimitry Andric SourceLocation RHS = getLoc(R);
1990b57cec5SDimitry Andric return SM.isBeforeInTranslationUnit(LHS, RHS);
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric
getLoc__anondd72c81d0111::PPEntityComp2020b57cec5SDimitry Andric SourceLocation getLoc(PreprocessedEntity *PPE) const {
2030b57cec5SDimitry Andric SourceRange Range = PPE->getSourceRange();
2040b57cec5SDimitry Andric return (Range.*getRangeLoc)();
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric };
2070b57cec5SDimitry Andric
2080b57cec5SDimitry Andric } // namespace
2090b57cec5SDimitry Andric
findBeginLocalPreprocessedEntity(SourceLocation Loc) const2100b57cec5SDimitry Andric unsigned PreprocessingRecord::findBeginLocalPreprocessedEntity(
2110b57cec5SDimitry Andric SourceLocation Loc) const {
2120b57cec5SDimitry Andric if (SourceMgr.isLoadedSourceLocation(Loc))
2130b57cec5SDimitry Andric return 0;
2140b57cec5SDimitry Andric
2150b57cec5SDimitry Andric size_t Count = PreprocessedEntities.size();
2160b57cec5SDimitry Andric size_t Half;
2170b57cec5SDimitry Andric std::vector<PreprocessedEntity *>::const_iterator
2180b57cec5SDimitry Andric First = PreprocessedEntities.begin();
2190b57cec5SDimitry Andric std::vector<PreprocessedEntity *>::const_iterator I;
2200b57cec5SDimitry Andric
2210b57cec5SDimitry Andric // Do a binary search manually instead of using std::lower_bound because
2220b57cec5SDimitry Andric // The end locations of entities may be unordered (when a macro expansion
2230b57cec5SDimitry Andric // is inside another macro argument), but for this case it is not important
2240b57cec5SDimitry Andric // whether we get the first macro expansion or its containing macro.
2250b57cec5SDimitry Andric while (Count > 0) {
2260b57cec5SDimitry Andric Half = Count/2;
2270b57cec5SDimitry Andric I = First;
2280b57cec5SDimitry Andric std::advance(I, Half);
2290b57cec5SDimitry Andric if (SourceMgr.isBeforeInTranslationUnit((*I)->getSourceRange().getEnd(),
2300b57cec5SDimitry Andric Loc)){
2310b57cec5SDimitry Andric First = I;
2320b57cec5SDimitry Andric ++First;
2330b57cec5SDimitry Andric Count = Count - Half - 1;
2340b57cec5SDimitry Andric } else
2350b57cec5SDimitry Andric Count = Half;
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric
2380b57cec5SDimitry Andric return First - PreprocessedEntities.begin();
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric
2410b57cec5SDimitry Andric unsigned
findEndLocalPreprocessedEntity(SourceLocation Loc) const2420b57cec5SDimitry Andric PreprocessingRecord::findEndLocalPreprocessedEntity(SourceLocation Loc) const {
2430b57cec5SDimitry Andric if (SourceMgr.isLoadedSourceLocation(Loc))
2440b57cec5SDimitry Andric return 0;
2450b57cec5SDimitry Andric
2460b57cec5SDimitry Andric auto I = llvm::upper_bound(PreprocessedEntities, Loc,
2470b57cec5SDimitry Andric PPEntityComp<&SourceRange::getBegin>(SourceMgr));
2480b57cec5SDimitry Andric return I - PreprocessedEntities.begin();
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric
2510b57cec5SDimitry Andric PreprocessingRecord::PPEntityID
addPreprocessedEntity(PreprocessedEntity * Entity)2520b57cec5SDimitry Andric PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
2530b57cec5SDimitry Andric assert(Entity);
2540b57cec5SDimitry Andric SourceLocation BeginLoc = Entity->getSourceRange().getBegin();
2550b57cec5SDimitry Andric
2560b57cec5SDimitry Andric if (isa<MacroDefinitionRecord>(Entity)) {
2570b57cec5SDimitry Andric assert((PreprocessedEntities.empty() ||
2580b57cec5SDimitry Andric !SourceMgr.isBeforeInTranslationUnit(
2590b57cec5SDimitry Andric BeginLoc,
2600b57cec5SDimitry Andric PreprocessedEntities.back()->getSourceRange().getBegin())) &&
2610b57cec5SDimitry Andric "a macro definition was encountered out-of-order");
2620b57cec5SDimitry Andric PreprocessedEntities.push_back(Entity);
2630b57cec5SDimitry Andric return getPPEntityID(PreprocessedEntities.size()-1, /*isLoaded=*/false);
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric
2660b57cec5SDimitry Andric // Check normal case, this entity begin location is after the previous one.
2670b57cec5SDimitry Andric if (PreprocessedEntities.empty() ||
2680b57cec5SDimitry Andric !SourceMgr.isBeforeInTranslationUnit(BeginLoc,
2690b57cec5SDimitry Andric PreprocessedEntities.back()->getSourceRange().getBegin())) {
2700b57cec5SDimitry Andric PreprocessedEntities.push_back(Entity);
2710b57cec5SDimitry Andric return getPPEntityID(PreprocessedEntities.size()-1, /*isLoaded=*/false);
2720b57cec5SDimitry Andric }
2730b57cec5SDimitry Andric
2740b57cec5SDimitry Andric // The entity's location is not after the previous one; this can happen with
2750b57cec5SDimitry Andric // include directives that form the filename using macros, e.g:
2760b57cec5SDimitry Andric // "#include MACRO(STUFF)"
2770b57cec5SDimitry Andric // or with macro expansions inside macro arguments where the arguments are
2780b57cec5SDimitry Andric // not expanded in the same order as listed, e.g:
2790b57cec5SDimitry Andric // \code
2800b57cec5SDimitry Andric // #define M1 1
2810b57cec5SDimitry Andric // #define M2 2
2820b57cec5SDimitry Andric // #define FM(x,y) y x
2830b57cec5SDimitry Andric // FM(M1, M2)
2840b57cec5SDimitry Andric // \endcode
2850b57cec5SDimitry Andric
2860b57cec5SDimitry Andric using pp_iter = std::vector<PreprocessedEntity *>::iterator;
2870b57cec5SDimitry Andric
2880b57cec5SDimitry Andric // Usually there are few macro expansions when defining the filename, do a
2890b57cec5SDimitry Andric // linear search for a few entities.
2900b57cec5SDimitry Andric unsigned count = 0;
2910b57cec5SDimitry Andric for (pp_iter RI = PreprocessedEntities.end(),
2920b57cec5SDimitry Andric Begin = PreprocessedEntities.begin();
2930b57cec5SDimitry Andric RI != Begin && count < 4; --RI, ++count) {
2940b57cec5SDimitry Andric pp_iter I = RI;
2950b57cec5SDimitry Andric --I;
2960b57cec5SDimitry Andric if (!SourceMgr.isBeforeInTranslationUnit(BeginLoc,
2970b57cec5SDimitry Andric (*I)->getSourceRange().getBegin())) {
2980b57cec5SDimitry Andric pp_iter insertI = PreprocessedEntities.insert(RI, Entity);
2990b57cec5SDimitry Andric return getPPEntityID(insertI - PreprocessedEntities.begin(),
3000b57cec5SDimitry Andric /*isLoaded=*/false);
3010b57cec5SDimitry Andric }
3020b57cec5SDimitry Andric }
3030b57cec5SDimitry Andric
3040b57cec5SDimitry Andric // Linear search unsuccessful. Do a binary search.
3050b57cec5SDimitry Andric pp_iter I =
3060b57cec5SDimitry Andric llvm::upper_bound(PreprocessedEntities, BeginLoc,
3070b57cec5SDimitry Andric PPEntityComp<&SourceRange::getBegin>(SourceMgr));
3080b57cec5SDimitry Andric pp_iter insertI = PreprocessedEntities.insert(I, Entity);
3090b57cec5SDimitry Andric return getPPEntityID(insertI - PreprocessedEntities.begin(),
3100b57cec5SDimitry Andric /*isLoaded=*/false);
3110b57cec5SDimitry Andric }
3120b57cec5SDimitry Andric
SetExternalSource(ExternalPreprocessingRecordSource & Source)3130b57cec5SDimitry Andric void PreprocessingRecord::SetExternalSource(
3140b57cec5SDimitry Andric ExternalPreprocessingRecordSource &Source) {
3150b57cec5SDimitry Andric assert(!ExternalSource &&
3160b57cec5SDimitry Andric "Preprocessing record already has an external source");
3170b57cec5SDimitry Andric ExternalSource = &Source;
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric
allocateLoadedEntities(unsigned NumEntities)3200b57cec5SDimitry Andric unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities) {
3210b57cec5SDimitry Andric unsigned Result = LoadedPreprocessedEntities.size();
3220b57cec5SDimitry Andric LoadedPreprocessedEntities.resize(LoadedPreprocessedEntities.size()
3230b57cec5SDimitry Andric + NumEntities);
3240b57cec5SDimitry Andric return Result;
3250b57cec5SDimitry Andric }
3260b57cec5SDimitry Andric
allocateSkippedRanges(unsigned NumRanges)3270b57cec5SDimitry Andric unsigned PreprocessingRecord::allocateSkippedRanges(unsigned NumRanges) {
3280b57cec5SDimitry Andric unsigned Result = SkippedRanges.size();
3290b57cec5SDimitry Andric SkippedRanges.resize(SkippedRanges.size() + NumRanges);
3300b57cec5SDimitry Andric SkippedRangesAllLoaded = false;
3310b57cec5SDimitry Andric return Result;
3320b57cec5SDimitry Andric }
3330b57cec5SDimitry Andric
ensureSkippedRangesLoaded()3340b57cec5SDimitry Andric void PreprocessingRecord::ensureSkippedRangesLoaded() {
3350b57cec5SDimitry Andric if (SkippedRangesAllLoaded || !ExternalSource)
3360b57cec5SDimitry Andric return;
3370b57cec5SDimitry Andric for (unsigned Index = 0; Index != SkippedRanges.size(); ++Index) {
3380b57cec5SDimitry Andric if (SkippedRanges[Index].isInvalid())
3390b57cec5SDimitry Andric SkippedRanges[Index] = ExternalSource->ReadSkippedRange(Index);
3400b57cec5SDimitry Andric }
3410b57cec5SDimitry Andric SkippedRangesAllLoaded = true;
3420b57cec5SDimitry Andric }
3430b57cec5SDimitry Andric
RegisterMacroDefinition(MacroInfo * Macro,MacroDefinitionRecord * Def)3440b57cec5SDimitry Andric void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
3450b57cec5SDimitry Andric MacroDefinitionRecord *Def) {
3460b57cec5SDimitry Andric MacroDefinitions[Macro] = Def;
3470b57cec5SDimitry Andric }
3480b57cec5SDimitry Andric
3490b57cec5SDimitry Andric /// Retrieve the preprocessed entity at the given ID.
getPreprocessedEntity(PPEntityID PPID)3500b57cec5SDimitry Andric PreprocessedEntity *PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID){
3510b57cec5SDimitry Andric if (PPID.ID < 0) {
3520b57cec5SDimitry Andric unsigned Index = -PPID.ID - 1;
3530b57cec5SDimitry Andric assert(Index < LoadedPreprocessedEntities.size() &&
3540b57cec5SDimitry Andric "Out-of bounds loaded preprocessed entity");
3550b57cec5SDimitry Andric return getLoadedPreprocessedEntity(Index);
3560b57cec5SDimitry Andric }
3570b57cec5SDimitry Andric
3580b57cec5SDimitry Andric if (PPID.ID == 0)
3590b57cec5SDimitry Andric return nullptr;
3600b57cec5SDimitry Andric unsigned Index = PPID.ID - 1;
3610b57cec5SDimitry Andric assert(Index < PreprocessedEntities.size() &&
3620b57cec5SDimitry Andric "Out-of bounds local preprocessed entity");
3630b57cec5SDimitry Andric return PreprocessedEntities[Index];
3640b57cec5SDimitry Andric }
3650b57cec5SDimitry Andric
3660b57cec5SDimitry Andric /// Retrieve the loaded preprocessed entity at the given index.
3670b57cec5SDimitry Andric PreprocessedEntity *
getLoadedPreprocessedEntity(unsigned Index)3680b57cec5SDimitry Andric PreprocessingRecord::getLoadedPreprocessedEntity(unsigned Index) {
3690b57cec5SDimitry Andric assert(Index < LoadedPreprocessedEntities.size() &&
3700b57cec5SDimitry Andric "Out-of bounds loaded preprocessed entity");
3710b57cec5SDimitry Andric assert(ExternalSource && "No external source to load from");
3720b57cec5SDimitry Andric PreprocessedEntity *&Entity = LoadedPreprocessedEntities[Index];
3730b57cec5SDimitry Andric if (!Entity) {
3740b57cec5SDimitry Andric Entity = ExternalSource->ReadPreprocessedEntity(Index);
3750b57cec5SDimitry Andric if (!Entity) // Failed to load.
3760b57cec5SDimitry Andric Entity = new (*this)
3770b57cec5SDimitry Andric PreprocessedEntity(PreprocessedEntity::InvalidKind, SourceRange());
3780b57cec5SDimitry Andric }
3790b57cec5SDimitry Andric return Entity;
3800b57cec5SDimitry Andric }
3810b57cec5SDimitry Andric
3820b57cec5SDimitry Andric MacroDefinitionRecord *
findMacroDefinition(const MacroInfo * MI)3830b57cec5SDimitry Andric PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
38406c3fb27SDimitry Andric return MacroDefinitions.lookup(MI);
3850b57cec5SDimitry Andric }
3860b57cec5SDimitry Andric
addMacroExpansion(const Token & Id,const MacroInfo * MI,SourceRange Range)3870b57cec5SDimitry Andric void PreprocessingRecord::addMacroExpansion(const Token &Id,
3880b57cec5SDimitry Andric const MacroInfo *MI,
3890b57cec5SDimitry Andric SourceRange Range) {
3900b57cec5SDimitry Andric // We don't record nested macro expansions.
3910b57cec5SDimitry Andric if (Id.getLocation().isMacroID())
3920b57cec5SDimitry Andric return;
3930b57cec5SDimitry Andric
3940b57cec5SDimitry Andric if (MI->isBuiltinMacro())
3950b57cec5SDimitry Andric addPreprocessedEntity(new (*this)
3960b57cec5SDimitry Andric MacroExpansion(Id.getIdentifierInfo(), Range));
3970b57cec5SDimitry Andric else if (MacroDefinitionRecord *Def = findMacroDefinition(MI))
3980b57cec5SDimitry Andric addPreprocessedEntity(new (*this) MacroExpansion(Def, Range));
3990b57cec5SDimitry Andric }
4000b57cec5SDimitry Andric
Ifdef(SourceLocation Loc,const Token & MacroNameTok,const MacroDefinition & MD)4010b57cec5SDimitry Andric void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok,
4020b57cec5SDimitry Andric const MacroDefinition &MD) {
4030b57cec5SDimitry Andric // This is not actually a macro expansion but record it as a macro reference.
4040b57cec5SDimitry Andric if (MD)
4050b57cec5SDimitry Andric addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
4060b57cec5SDimitry Andric MacroNameTok.getLocation());
4070b57cec5SDimitry Andric }
4080b57cec5SDimitry Andric
Elifdef(SourceLocation Loc,const Token & MacroNameTok,const MacroDefinition & MD)409fe6060f1SDimitry Andric void PreprocessingRecord::Elifdef(SourceLocation Loc, const Token &MacroNameTok,
410fe6060f1SDimitry Andric const MacroDefinition &MD) {
411fe6060f1SDimitry Andric // This is not actually a macro expansion but record it as a macro reference.
412fe6060f1SDimitry Andric if (MD)
413fe6060f1SDimitry Andric addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
414fe6060f1SDimitry Andric MacroNameTok.getLocation());
415fe6060f1SDimitry Andric }
416fe6060f1SDimitry Andric
Ifndef(SourceLocation Loc,const Token & MacroNameTok,const MacroDefinition & MD)4170b57cec5SDimitry Andric void PreprocessingRecord::Ifndef(SourceLocation Loc, const Token &MacroNameTok,
4180b57cec5SDimitry Andric const MacroDefinition &MD) {
4190b57cec5SDimitry Andric // This is not actually a macro expansion but record it as a macro reference.
4200b57cec5SDimitry Andric if (MD)
4210b57cec5SDimitry Andric addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
4220b57cec5SDimitry Andric MacroNameTok.getLocation());
4230b57cec5SDimitry Andric }
4240b57cec5SDimitry Andric
Elifndef(SourceLocation Loc,const Token & MacroNameTok,const MacroDefinition & MD)425fe6060f1SDimitry Andric void PreprocessingRecord::Elifndef(SourceLocation Loc,
426fe6060f1SDimitry Andric const Token &MacroNameTok,
427fe6060f1SDimitry Andric const MacroDefinition &MD) {
428fe6060f1SDimitry Andric // This is not actually a macro expansion but record it as a macro reference.
429fe6060f1SDimitry Andric if (MD)
430fe6060f1SDimitry Andric addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
431fe6060f1SDimitry Andric MacroNameTok.getLocation());
432fe6060f1SDimitry Andric }
433fe6060f1SDimitry Andric
Defined(const Token & MacroNameTok,const MacroDefinition & MD,SourceRange Range)4340b57cec5SDimitry Andric void PreprocessingRecord::Defined(const Token &MacroNameTok,
4350b57cec5SDimitry Andric const MacroDefinition &MD,
4360b57cec5SDimitry Andric SourceRange Range) {
4370b57cec5SDimitry Andric // This is not actually a macro expansion but record it as a macro reference.
4380b57cec5SDimitry Andric if (MD)
4390b57cec5SDimitry Andric addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
4400b57cec5SDimitry Andric MacroNameTok.getLocation());
4410b57cec5SDimitry Andric }
4420b57cec5SDimitry Andric
SourceRangeSkipped(SourceRange Range,SourceLocation EndifLoc)4430b57cec5SDimitry Andric void PreprocessingRecord::SourceRangeSkipped(SourceRange Range,
4440b57cec5SDimitry Andric SourceLocation EndifLoc) {
4450b57cec5SDimitry Andric assert(Range.isValid());
4460b57cec5SDimitry Andric SkippedRanges.emplace_back(Range.getBegin(), EndifLoc);
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric
MacroExpands(const Token & Id,const MacroDefinition & MD,SourceRange Range,const MacroArgs * Args)4490b57cec5SDimitry Andric void PreprocessingRecord::MacroExpands(const Token &Id,
4500b57cec5SDimitry Andric const MacroDefinition &MD,
4510b57cec5SDimitry Andric SourceRange Range,
4520b57cec5SDimitry Andric const MacroArgs *Args) {
4530b57cec5SDimitry Andric addMacroExpansion(Id, MD.getMacroInfo(), Range);
4540b57cec5SDimitry Andric }
4550b57cec5SDimitry Andric
MacroDefined(const Token & Id,const MacroDirective * MD)4560b57cec5SDimitry Andric void PreprocessingRecord::MacroDefined(const Token &Id,
4570b57cec5SDimitry Andric const MacroDirective *MD) {
4580b57cec5SDimitry Andric const MacroInfo *MI = MD->getMacroInfo();
4590b57cec5SDimitry Andric SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
4600b57cec5SDimitry Andric MacroDefinitionRecord *Def =
4610b57cec5SDimitry Andric new (*this) MacroDefinitionRecord(Id.getIdentifierInfo(), R);
4620b57cec5SDimitry Andric addPreprocessedEntity(Def);
4630b57cec5SDimitry Andric MacroDefinitions[MI] = Def;
4640b57cec5SDimitry Andric }
4650b57cec5SDimitry Andric
MacroUndefined(const Token & Id,const MacroDefinition & MD,const MacroDirective * Undef)4660b57cec5SDimitry Andric void PreprocessingRecord::MacroUndefined(const Token &Id,
4670b57cec5SDimitry Andric const MacroDefinition &MD,
4680b57cec5SDimitry Andric const MacroDirective *Undef) {
4690b57cec5SDimitry Andric MD.forAllDefinitions([&](MacroInfo *MI) { MacroDefinitions.erase(MI); });
4700b57cec5SDimitry Andric }
4710b57cec5SDimitry Andric
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,OptionalFileEntryRef File,StringRef SearchPath,StringRef RelativePath,const Module * Imported,SrcMgr::CharacteristicKind FileType)4720b57cec5SDimitry Andric void PreprocessingRecord::InclusionDirective(
473bdd1243dSDimitry Andric SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
474bdd1243dSDimitry Andric bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
475bdd1243dSDimitry Andric StringRef SearchPath, StringRef RelativePath, const Module *Imported,
4760b57cec5SDimitry Andric SrcMgr::CharacteristicKind FileType) {
4770b57cec5SDimitry Andric InclusionDirective::InclusionKind Kind = InclusionDirective::Include;
4780b57cec5SDimitry Andric
4790b57cec5SDimitry Andric switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
4800b57cec5SDimitry Andric case tok::pp_include:
4810b57cec5SDimitry Andric Kind = InclusionDirective::Include;
4820b57cec5SDimitry Andric break;
4830b57cec5SDimitry Andric
4840b57cec5SDimitry Andric case tok::pp_import:
4850b57cec5SDimitry Andric Kind = InclusionDirective::Import;
4860b57cec5SDimitry Andric break;
4870b57cec5SDimitry Andric
4880b57cec5SDimitry Andric case tok::pp_include_next:
4890b57cec5SDimitry Andric Kind = InclusionDirective::IncludeNext;
4900b57cec5SDimitry Andric break;
4910b57cec5SDimitry Andric
4920b57cec5SDimitry Andric case tok::pp___include_macros:
4930b57cec5SDimitry Andric Kind = InclusionDirective::IncludeMacros;
4940b57cec5SDimitry Andric break;
4950b57cec5SDimitry Andric
4960b57cec5SDimitry Andric default:
4970b57cec5SDimitry Andric llvm_unreachable("Unknown include directive kind");
4980b57cec5SDimitry Andric }
4990b57cec5SDimitry Andric
5000b57cec5SDimitry Andric SourceLocation EndLoc;
5010b57cec5SDimitry Andric if (!IsAngled) {
5020b57cec5SDimitry Andric EndLoc = FilenameRange.getBegin();
5030b57cec5SDimitry Andric } else {
5040b57cec5SDimitry Andric EndLoc = FilenameRange.getEnd();
5050b57cec5SDimitry Andric if (FilenameRange.isCharRange())
5060b57cec5SDimitry Andric EndLoc = EndLoc.getLocWithOffset(-1); // the InclusionDirective expects
5070b57cec5SDimitry Andric // a token range.
5080b57cec5SDimitry Andric }
5090b57cec5SDimitry Andric clang::InclusionDirective *ID =
5100b57cec5SDimitry Andric new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled,
5110b57cec5SDimitry Andric (bool)Imported, File,
5120b57cec5SDimitry Andric SourceRange(HashLoc, EndLoc));
5130b57cec5SDimitry Andric addPreprocessedEntity(ID);
5140b57cec5SDimitry Andric }
5150b57cec5SDimitry Andric
getTotalMemory() const5160b57cec5SDimitry Andric size_t PreprocessingRecord::getTotalMemory() const {
5170b57cec5SDimitry Andric return BumpAlloc.getTotalMemory()
5180b57cec5SDimitry Andric + llvm::capacity_in_bytes(MacroDefinitions)
5190b57cec5SDimitry Andric + llvm::capacity_in_bytes(PreprocessedEntities)
5200b57cec5SDimitry Andric + llvm::capacity_in_bytes(LoadedPreprocessedEntities)
5210b57cec5SDimitry Andric + llvm::capacity_in_bytes(SkippedRanges);
5220b57cec5SDimitry Andric }
523