clang: lib/Lex/PreprocessingRecord.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

22#include "llvm/ADT/DenseMap.h"

23#include "llvm/ADT/iterator_range.h"

24#include "llvm/Support/Capacity.h"

25#include "llvm/Support/ErrorHandling.h"

26#include

27#include

28#include

29#include

30#include

31#include

32#include

33

34using namespace clang;

35

37 default;

38

41 bool InQuotes, bool ImportedModule,

45 Kind(Kind), ImportedModule(ImportedModule), File(File) {

46 char *Memory = (char *)PPRec.Allocate(FileName.size() + 1, alignof(char));

47 memcpy(Memory, FileName.data(), FileName.size());

48 Memory[FileName.size()] = 0;

49 this->FileName = StringRef(Memory, FileName.size());

50}

51

53

54

55

56llvm::iterator_rangePreprocessingRecord::iterator

58 if (Range.isInvalid())

60

61 if (CachedRangeQuery.Range == Range) {

62 return llvm::make_range(iterator(this, CachedRangeQuery.Result.first),

63 iterator(this, CachedRangeQuery.Result.second));

64 }

65

66 std::pair<int, int> Res = getPreprocessedEntitiesInRangeSlow(Range);

67

68 CachedRangeQuery.Range = Range;

69 CachedRangeQuery.Result = Res;

70

71 return llvm::make_range(iterator(this, Res.first),

73}

74

78 if (!PPE)

79 return false;

80

83 return false;

84

85 return SM.isInFileID(SM.getFileLoc(Loc), FID);

86}

87

88

89

90

91

92

93

94

97 return false;

98

99 int Pos = std::distance(iterator(this, 0), PPEI);

100 if (Pos < 0) {

101 if (unsigned(-Pos-1) >= LoadedPreprocessedEntities.size()) {

102 assert(0 && "Out-of bounds loaded preprocessed entity");

103 return false;

104 }

105 assert(ExternalSource && "No external source to load from");

106 unsigned LoadedIndex = LoadedPreprocessedEntities.size()+Pos;

107 if (PreprocessedEntity *PPE = LoadedPreprocessedEntities[LoadedIndex])

109

110

111

112 if (std::optional IsInFile =

113 ExternalSource->isPreprocessedEntityInFileID(LoadedIndex, FID))

114 return *IsInFile;

115

116

117

119 getLoadedPreprocessedEntity(LoadedIndex),

120 FID, SourceMgr);

121 }

122

123 if (unsigned(Pos) >= PreprocessedEntities.size()) {

124 assert(0 && "Out-of bounds local preprocessed entity");

125 return false;

126 }

128 FID, SourceMgr);

129}

130

131

132

133std::pair<int, int>

134PreprocessingRecord::getPreprocessedEntitiesInRangeSlow(SourceRange Range) {

137

138 std::pair<unsigned, unsigned>

139 Local = findLocalPreprocessedEntitiesInRange(Range);

140

141

143 return std::make_pair(Local.first, Local.second);

144

145 std::pair<unsigned, unsigned>

147

148

149 if (Loaded.first == Loaded.second)

150 return std::make_pair(Local.first, Local.second);

151

152 unsigned TotalLoaded = LoadedPreprocessedEntities.size();

153

154

155 if (Local.first == Local.second)

156 return std::make_pair(int(Loaded.first)-TotalLoaded,

157 int(Loaded.second)-TotalLoaded);

158

159

160 return std::make_pair(int(Loaded.first)-TotalLoaded, Local.second);

161}

162

163std::pair<unsigned, unsigned>

164PreprocessingRecord::findLocalPreprocessedEntitiesInRange(

167 return std::make_pair(0,0);

169

170 unsigned Begin = findBeginLocalPreprocessedEntity(Range.getBegin());

171 unsigned End = findEndLocalPreprocessedEntity(Range.getEnd());

172 return std::make_pair(Begin, End);

173}

174

175namespace {

176

177template <SourceLocation (SourceRange::*getRangeLoc)() const>

178struct PPEntityComp {

179 const SourceManager &SM;

180

181 explicit PPEntityComp(const SourceManager &SM) : SM(SM) {}

182

183 bool operator()(PreprocessedEntity *L, PreprocessedEntity *R) const {

184 SourceLocation LHS = getLoc(L);

185 SourceLocation RHS = getLoc(R);

186 return SM.isBeforeInTranslationUnit(LHS, RHS);

187 }

188

189 bool operator()(PreprocessedEntity *L, SourceLocation RHS) const {

190 SourceLocation LHS = getLoc(L);

191 return SM.isBeforeInTranslationUnit(LHS, RHS);

192 }

193

194 bool operator()(SourceLocation LHS, PreprocessedEntity *R) const {

195 SourceLocation RHS = getLoc(R);

196 return SM.isBeforeInTranslationUnit(LHS, RHS);

197 }

198

199 SourceLocation getLoc(PreprocessedEntity *PPE) const {

201 return (Range.*getRangeLoc)();

202 }

203};

204

205}

206

207unsigned PreprocessingRecord::findBeginLocalPreprocessedEntity(

209 if (SourceMgr.isLoadedSourceLocation(Loc))

210 return 0;

211

212 size_t Count = PreprocessedEntities.size();

214 std::vector<PreprocessedEntity *>::const_iterator

215 First = PreprocessedEntities.begin();

216 std::vector<PreprocessedEntity *>::const_iterator I;

217

218

219

220

221

222 while (Count > 0) {

223 Half = Count/2;

225 std::advance(I, Half);

226 if (SourceMgr.isBeforeInTranslationUnit((*I)->getSourceRange().getEnd(),

227 Loc)){

230 Count = Count - Half - 1;

231 } else

232 Count = Half;

233 }

234

235 return First - PreprocessedEntities.begin();

236}

237

238unsigned

239PreprocessingRecord::findEndLocalPreprocessedEntity(SourceLocation Loc) const {

240 if (SourceMgr.isLoadedSourceLocation(Loc))

241 return 0;

242

243 auto I = llvm::upper_bound(PreprocessedEntities, Loc,

244 PPEntityComp<&SourceRange::getBegin>(SourceMgr));

245 return I - PreprocessedEntities.begin();

246}

247

248PreprocessingRecord::PPEntityID

250 assert(Entity);

252

254 assert((PreprocessedEntities.empty() ||

255 !SourceMgr.isBeforeInTranslationUnit(

256 BeginLoc,

257 PreprocessedEntities.back()->getSourceRange().getBegin())) &&

258 "a macro definition was encountered out-of-order");

259 PreprocessedEntities.push_back(Entity);

260 return getPPEntityID(PreprocessedEntities.size()-1, false);

261 }

262

263

264 if (PreprocessedEntities.empty() ||

265 !SourceMgr.isBeforeInTranslationUnit(BeginLoc,

266 PreprocessedEntities.back()->getSourceRange().getBegin())) {

267 PreprocessedEntities.push_back(Entity);

268 return getPPEntityID(PreprocessedEntities.size()-1, false);

269 }

270

271

272

273

274

275

276

277

278

279

280

281

282

283 using pp_iter = std::vector<PreprocessedEntity *>::iterator;

284

285

286

287 unsigned count = 0;

288 for (pp_iter RI = PreprocessedEntities.end(),

289 Begin = PreprocessedEntities.begin();

290 RI != Begin && count < 4; --RI, ++count) {

291 pp_iter I = RI;

292 --I;

293 if (!SourceMgr.isBeforeInTranslationUnit(BeginLoc,

294 (*I)->getSourceRange().getBegin())) {

295 pp_iter insertI = PreprocessedEntities.insert(RI, Entity);

296 return getPPEntityID(insertI - PreprocessedEntities.begin(),

297 false);

298 }

299 }

300

301

302 pp_iter I =

303 llvm::upper_bound(PreprocessedEntities, BeginLoc,

304 PPEntityComp<&SourceRange::getBegin>(SourceMgr));

305 pp_iter insertI = PreprocessedEntities.insert(I, Entity);

306 return getPPEntityID(insertI - PreprocessedEntities.begin(),

307 false);

308}

309

312 assert(!ExternalSource &&

313 "Preprocessing record already has an external source");

314 ExternalSource = &Source;

315}

316

317unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities) {

318 unsigned Result = LoadedPreprocessedEntities.size();

319 LoadedPreprocessedEntities.resize(LoadedPreprocessedEntities.size()

320 + NumEntities);

322}

323

324unsigned PreprocessingRecord::allocateSkippedRanges(unsigned NumRanges) {

325 unsigned Result = SkippedRanges.size();

326 SkippedRanges.resize(SkippedRanges.size() + NumRanges);

327 SkippedRangesAllLoaded = false;

328 return Result;

329}

330

331void PreprocessingRecord::ensureSkippedRangesLoaded() {

332 if (SkippedRangesAllLoaded || !ExternalSource)

333 return;

334 for (unsigned Index = 0; Index != SkippedRanges.size(); ++Index) {

335 if (SkippedRanges[Index].isInvalid())

336 SkippedRanges[Index] = ExternalSource->ReadSkippedRange(Index);

337 }

338 SkippedRangesAllLoaded = true;

339}

340

341void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,

343 MacroDefinitions[Macro] = Def;

344}

345

346

347PreprocessedEntity *PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID){

348 if (PPID.ID < 0) {

349 unsigned Index = -PPID.ID - 1;

350 assert(Index < LoadedPreprocessedEntities.size() &&

351 "Out-of bounds loaded preprocessed entity");

352 return getLoadedPreprocessedEntity(Index);

353 }

354

355 if (PPID.ID == 0)

356 return nullptr;

357 unsigned Index = PPID.ID - 1;

358 assert(Index < PreprocessedEntities.size() &&

359 "Out-of bounds local preprocessed entity");

360 return PreprocessedEntities[Index];

361}

362

363

365PreprocessingRecord::getLoadedPreprocessedEntity(unsigned Index) {

366 assert(Index < LoadedPreprocessedEntities.size() &&

367 "Out-of bounds loaded preprocessed entity");

368 assert(ExternalSource && "No external source to load from");

369 PreprocessedEntity *&Entity = LoadedPreprocessedEntities[Index];

370 if (!Entity) {

371 Entity = ExternalSource->ReadPreprocessedEntity(Index);

372 if (!Entity)

373 Entity = new (*this)

375 }

376 return Entity;

377}

378

381 return MacroDefinitions.lookup(MI);

382}

383

384void PreprocessingRecord::addMacroExpansion(const Token &Id,

387

389 return;

390

396}

397

398void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok,

400

401 if (MD)

402 addMacroExpansion(MacroNameTok, MD.getMacroInfo(),

404}

405

406void PreprocessingRecord::Elifdef(SourceLocation Loc, const Token &MacroNameTok,

408

409 if (MD)

410 addMacroExpansion(MacroNameTok, MD.getMacroInfo(),

412}

413

414void PreprocessingRecord::Ifndef(SourceLocation Loc, const Token &MacroNameTok,

416

417 if (MD)

418 addMacroExpansion(MacroNameTok, MD.getMacroInfo(),

420}

421

422void PreprocessingRecord::Elifndef(SourceLocation Loc,

423 const Token &MacroNameTok,

425

426 if (MD)

427 addMacroExpansion(MacroNameTok, MD.getMacroInfo(),

429}

430

431void PreprocessingRecord::Defined(const Token &MacroNameTok,

434

435 if (MD)

436 addMacroExpansion(MacroNameTok, MD.getMacroInfo(),

438}

439

440void PreprocessingRecord::SourceRangeSkipped(SourceRange Range,

442 assert(Range.isValid());

443 SkippedRanges.emplace_back(Range.getBegin(), EndifLoc);

444}

445

446void PreprocessingRecord::MacroExpands(const Token &Id,

451}

452

453void PreprocessingRecord::MacroDefined(const Token &Id,

457 MacroDefinitionRecord *Def =

460 MacroDefinitions[MI] = Def;

461}

462

463void PreprocessingRecord::MacroUndefined(const Token &Id,

466 MD.forAllDefinitions([&](MacroInfo *MI) { MacroDefinitions.erase(MI); });

467}

468

469void PreprocessingRecord::InclusionDirective(

472 StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,

475

477 case tok::pp_include:

479 break;

480

481 case tok::pp_import:

483 break;

484

485 case tok::pp_include_next:

487 break;

488

489 case tok::pp___include_macros:

491 break;

492

493 default:

494 llvm_unreachable("Unknown include directive kind");

495 }

496

497 SourceLocation EndLoc;

498 if (!IsAngled) {

499 EndLoc = FilenameRange.getBegin();

500 } else {

501 EndLoc = FilenameRange.getEnd();

503 EndLoc = EndLoc.getLocWithOffset(-1);

504

505 }

506 clang::InclusionDirective *ID = new (*this) clang::InclusionDirective(

507 *this, Kind, FileName, !IsAngled, ModuleImported, File,

508 SourceRange(HashLoc, EndLoc));

510}

511

513 return BumpAlloc.getTotalMemory()

514 + llvm::capacity_in_bytes(MacroDefinitions)

515 + llvm::capacity_in_bytes(PreprocessedEntities)

516 + llvm::capacity_in_bytes(LoadedPreprocessedEntities)

517 + llvm::capacity_in_bytes(SkippedRanges);

518}

Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.

Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.

llvm::MachO::FileType FileType

Defines the clang::MacroInfo and clang::MacroDirective classes.

static bool isPreprocessedEntityIfInFileID(PreprocessedEntity *PPE, FileID FID, SourceManager &SM)

Definition PreprocessingRecord.cpp:75

Defines the clang::SourceLocation class and associated facilities.

static bool isInvalid(LocType Loc, bool *Invalid)

Defines the SourceManager interface.

Defines the clang::TokenKind enum and support functions.

__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)

Represents a character-granular source range.

SourceLocation getEnd() const

SourceLocation getBegin() const

An abstract class that should be subclassed by any external source of preprocessing record entries.

virtual ~ExternalPreprocessingRecordSource()

An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...

tok::PPKeywordKind getPPKeywordID() const

Return the preprocessor keyword ID for this identifier.

InclusionKind

The kind of inclusion directives known to the preprocessor.

@ IncludeMacros

A Clang #__include_macros directive.

@ Import

An Objective-C #import directive.

@ IncludeNext

A GNU #include_next directive.

@ Include

An #include directive.

InclusionDirective(PreprocessingRecord &PPRec, InclusionKind Kind, StringRef FileName, bool InQuotes, bool ImportedModule, OptionalFileEntryRef File, SourceRange Range)

Definition PreprocessingRecord.cpp:39

MacroArgs - An instance of this class captures information about the formal arguments specified to a ...

Record the location of a macro definition.

A description of the current definition of a macro.

MacroInfo * getMacroInfo() const

Get the MacroInfo that should be used for this definition.

void forAllDefinitions(Fn F) const

Encapsulates changes to the "macros namespace" (the location where the macro name became active,...

const MacroInfo * getMacroInfo() const

Records the location of a macro expansion.

Encapsulates the data about a macro definition (e.g.

SourceLocation getDefinitionEndLoc() const

Return the location of the last token in the macro.

bool isBuiltinMacro() const

Return true if this macro requires processing before expansion.

SourceLocation getDefinitionLoc() const

Return the location that the macro was defined at.

Describes a module or submodule.

Base class that describes a preprocessed entity, which may be a preprocessor directive or macro expan...

@ InvalidKind

Indicates a problem trying to load the preprocessed entity.

SourceRange getSourceRange() const LLVM_READONLY

Retrieve the source range that covers this entire preprocessed entity.

PreprocessingDirective(EntityKind Kind, SourceRange Range)

Iteration over the preprocessed entities.

A record of the steps taken while preprocessing a source file, including the various preprocessing di...

PreprocessingRecord(SourceManager &SM)

Construct a new preprocessing record.

Definition PreprocessingRecord.cpp:52

void * Allocate(unsigned Size, unsigned Align=8)

Allocate memory in the preprocessing record.

llvm::iterator_range< iterator > getPreprocessedEntitiesInRange(SourceRange R)

Returns a range of preprocessed entities that source range R encompasses.

Definition PreprocessingRecord.cpp:57

MacroDefinitionRecord * findMacroDefinition(const MacroInfo *MI)

Retrieve the macro definition that corresponds to the given MacroInfo.

Definition PreprocessingRecord.cpp:380

PPEntityID addPreprocessedEntity(PreprocessedEntity *Entity)

Add a new preprocessed entity to this record.

Definition PreprocessingRecord.cpp:249

bool isEntityInFileID(iterator PPEI, FileID FID)

Returns true if the preprocessed entity that PPEI iterator points to is coming from the file FID.

Definition PreprocessingRecord.cpp:95

size_t getTotalMemory() const

Definition PreprocessingRecord.cpp:512

void SetExternalSource(ExternalPreprocessingRecordSource &Source)

Set the external source for preprocessed entities.

Definition PreprocessingRecord.cpp:310

Encodes a location in the source.

SourceLocation getLocWithOffset(IntTy Offset) const

Return a source location with the specified offset from this SourceLocation.

This class handles loading and caching of source files into memory.

A trivial tuple used to represent a source range.

SourceLocation getEnd() const

SourceLocation getBegin() const

Token - This structure provides full information about a lexed token.

IdentifierInfo * getIdentifierInfo() const

SourceLocation getLocation() const

Return a source location identifier for the specified offset in the current file.

@ InclusionDirectiveKind

An inclusion directive, such as #include, #import, or #include_next.

CharacteristicKind

Indicates whether a file or directory holds normal user code, system code, or system code which is im...

The JSON file list parser is used to communicate input to InstallAPI.

bool isa(CodeGen::Address addr)

CustomizableOptional< FileEntryRef > OptionalFileEntryRef

@ Result

The result type of a method or function.