clang: lib/Basic/SourceManager.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
19#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/MapVector.h"
21#include "llvm/ADT/STLExtras.h"
22#include "llvm/ADT/SmallVector.h"
23#include "llvm/ADT/Statistic.h"
24#include "llvm/ADT/StringRef.h"
25#include "llvm/ADT/StringSwitch.h"
26#include "llvm/Support/Allocator.h"
27#include "llvm/Support/AutoConvert.h"
28#include "llvm/Support/Capacity.h"
29#include "llvm/Support/Compiler.h"
30#include "llvm/Support/Endian.h"
31#include "llvm/Support/ErrorHandling.h"
32#include "llvm/Support/FileSystem.h"
33#include "llvm/Support/MathExtras.h"
34#include "llvm/Support/MemoryBuffer.h"
35#include "llvm/Support/Path.h"
36#include "llvm/Support/raw_ostream.h"
37#include
38#include
39#include
40#include
41#include
42#include
43#include
44#include
45#include
46
47using namespace clang;
48using namespace SrcMgr;
49using llvm::MemoryBuffer;
50
51#define DEBUG_TYPE "source-manager"
52
53
54
55STATISTIC(MaxUsedSLocBytes, "Maximum number of bytes used by source locations "
56 "(both loaded and local).");
57
58
59
60
61
62
63
65 return Buffer ? Buffer->getBufferSize() : 0;
66}
67
68
69
71 if (Buffer == nullptr) {
72 assert(0 && "Buffer should never be null");
73 return llvm::MemoryBuffer::MemoryBuffer_Malloc;
74 }
75 return Buffer->getBufferKind();
76}
77
78
79
80
81
83 return Buffer ? (unsigned)Buffer->getBufferSize()
85}
86
88
89
90
91 const char *InvalidBOM =
92 llvm::StringSwitch<const char *>(BufStr)
93 .StartsWith(llvm::StringLiteral::withInnerNUL("\x00\x00\xFE\xFF"),
94 "UTF-32 (BE)")
95 .StartsWith(llvm::StringLiteral::withInnerNUL("\xFF\xFE\x00\x00"),
96 "UTF-32 (LE)")
97 .StartsWith("\xFE\xFF", "UTF-16 (BE)")
98 .StartsWith("\xFF\xFE", "UTF-16 (LE)")
99 .StartsWith("\x2B\x2F\x76", "UTF-7")
100 .StartsWith("\xF7\x64\x4C", "UTF-1")
101 .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC")
102 .StartsWith("\x0E\xFE\xFF", "SCSU")
103 .StartsWith("\xFB\xEE\x28", "BOCU-1")
104 .StartsWith("\x84\x31\x95\x33", "GB-18030")
105 .Default(nullptr);
106
107 return InvalidBOM;
108}
109
110std::optionalllvm::MemoryBufferRef
113
114
116 return std::nullopt;
117 if (Buffer)
118 return Buffer->getMemBufferRef();
120 return std::nullopt;
121
122
123
125
127
128
129
130
131
132
133 if (!BufferOrError) {
134 Diag.Report(Loc, diag::err_cannot_open_file)
136
137 return std::nullopt;
138 }
139
140 Buffer = std::move(*BufferOrError);
141
142
143
144
145
146
147
148
149
150
151 if (Buffer->getBufferSize() >= std::numeric_limits::max()) {
153
154 return std::nullopt;
155 }
156
157
158
159
160
161
166
167 return std::nullopt;
168 }
169
170
171
172
173 StringRef BufStr = Buffer->getBuffer();
175
176 if (InvalidBOM) {
177 Diag.Report(Loc, diag::err_unsupported_bom)
179 return std::nullopt;
180 }
181
182
184 return Buffer->getMemBufferRef();
185}
186
188 auto IterBool = FilenameIDs.try_emplace(Name, FilenamesByID.size());
189 if (IterBool.second)
190 FilenamesByID.push_back(&*IterBool.first);
191 return IterBool.first->second;
192}
193
194
195
196
197
198
199
201 int FilenameID, unsigned EntryExit,
203 std::vector &Entries = LineEntries[FID];
204
205 assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
206 "Adding line entries out of order!");
207
208 unsigned IncludeOffset = 0;
209 if (EntryExit == 1) {
210
211 IncludeOffset = Offset-1;
212 } else {
213 const auto *PrevEntry = Entries.empty() ? nullptr : &Entries.back();
214 if (EntryExit == 2) {
215
216 assert(PrevEntry && PrevEntry->IncludeOffset &&
217 "PPDirectives should have caught case when popping empty include "
218 "stack");
219 PrevEntry = FindNearestLineEntry(FID, PrevEntry->IncludeOffset);
220 }
221 if (PrevEntry) {
222 IncludeOffset = PrevEntry->IncludeOffset;
223 if (FilenameID == -1) {
224
225
226 FilenameID = PrevEntry->FilenameID;
227 }
228 }
229 }
230
231 Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, FileKind,
232 IncludeOffset));
233}
234
235
236
238 unsigned Offset) {
239 const std::vector &Entries = LineEntries[FID];
240 assert(!Entries.empty() && "No #line entries for this FID after all!");
241
242
243
244 if (Entries.back().FileOffset <= Offset)
245 return &Entries.back();
246
247
248 std::vector::const_iterator I = llvm::upper_bound(Entries, Offset);
249 if (I == Entries.begin())
250 return nullptr;
251 return &*--I;
252}
253
254
255
257 const std::vector &Entries) {
258 LineEntries[FID] = Entries;
259}
260
261
263 return getLineTable().getLineTableFilenameID(Name);
264}
265
266
267
268
270 int FilenameID, bool IsFileEntry,
271 bool IsFileExit,
273 std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
274
278 return;
279
281
282
284
285 (void) getLineTable();
286
287 unsigned EntryExit = 0;
288 if (IsFileEntry)
289 EntryExit = 1;
290 else if (IsFileExit)
291 EntryExit = 2;
292
293 LineTable->AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID,
294 EntryExit, FileKind);
295}
296
298 if (!LineTable)
300 return *LineTable;
301}
302
303
304
305
306
308 bool UserFilesAreVolatile)
309 : Diag(Diag), FileMgr(FileMgr), UserFilesAreVolatile(UserFilesAreVolatile) {
312}
313
315
316
317
318 for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i) {
319 if (MemBufferInfos[i]) {
320 MemBufferInfos[i]->~ContentCache();
321 ContentCacheAlloc.Deallocate(MemBufferInfos[i]);
322 }
323 }
324 for (auto I = FileInfos.begin(), E = FileInfos.end(); I != E; ++I) {
325 if (I->second) {
326 I->second->~ContentCache();
327 ContentCacheAlloc.Deallocate(I->second);
328 }
329 }
330}
331
333 MainFileID = FileID();
334 LocalSLocEntryTable.clear();
335 LoadedSLocEntryTable.clear();
336 SLocEntryLoaded.clear();
337 SLocEntryOffsetLoaded.clear();
338 LastLineNoFileIDQuery = FileID();
339 LastLineNoContentCache = nullptr;
340 LastFileIDLookup = FileID();
341
342 IncludedLocMap.clear();
343 if (LineTable)
344 LineTable->clear();
345
346
347 NextLocalOffset = 0;
348 CurrentLoadedOffset = MaxLoadedOffset;
350}
351
353 assert(MainFileID.isValid() && "expected initialized SourceManager");
355 return FE->getUID() == SourceFile.getUID();
356 return false;
357}
358
360 assert(MainFileID.isInvalid() && "expected uninitialized SourceManager");
361
365 Clone->ContentsEntry = Cache->ContentsEntry;
366 Clone->BufferOverridden = Cache->BufferOverridden;
367 Clone->IsFileVolatile = Cache->IsFileVolatile;
368 Clone->IsTransient = Cache->IsTransient;
369 Clone->setUnownedBuffer(Cache->getBufferIfLoaded());
370 return Clone;
371 };
372
373
374 for (unsigned I = 0, N = Old.LoadedSLocEntryTable.size(); I != N; ++I)
375 if (!Old.SLocEntryLoaded[I])
376 Old.loadSLocEntry(I, nullptr);
377
378
379 for (auto &FileInfo : Old.FileInfos) {
381 if (Slot)
382 continue;
383 Slot = CloneContentCache(FileInfo.second);
384 }
385}
386
388 bool isSystemFile) {
389
391 if (Entry)
392 return *Entry;
393
394
395 Entry = ContentCacheAlloc.Allocate<ContentCache>();
396
397 if (OverriddenFilesInfo) {
398
399
400 auto overI = OverriddenFilesInfo->OverriddenFiles.find(FileEnt);
401 if (overI == OverriddenFilesInfo->OverriddenFiles.end())
403 else
404 new (Entry) ContentCache(OverridenFilesKeepOriginalName ? FileEnt
405 : overI->second,
406 overI->second);
407 } else {
409 }
410
411 Entry->IsFileVolatile = UserFilesAreVolatile && !isSystemFile;
414
415 return *Entry;
416}
417
418
419
420ContentCache &SourceManager::createMemBufferContentCache(
421 std::unique_ptrllvm::MemoryBuffer Buffer) {
422
425 MemBufferInfos.push_back(Entry);
426 Entry->setBuffer(std::move(Buffer));
427 return *Entry;
428}
429
430const SrcMgr::SLocEntry &SourceManager::loadSLocEntry(unsigned Index,
433}
434
436 assert(!SLocEntryLoaded[Index]);
437 if (ExternalSLocEntries->ReadSLocEntry(-(static_cast<int>(Index) + 2))) {
440
441 if (!SLocEntryLoaded[Index]) {
442
443 if (!FakeSLocEntryForRecovery)
444 FakeSLocEntryForRecovery = std::make_unique(SLocEntry::get(
447 return *FakeSLocEntryForRecovery;
448 }
449 }
450
451 return LoadedSLocEntryTable[Index];
452}
453
454std::pair<int, SourceLocation::UIntTy>
457 assert(ExternalSLocEntries && "Don't have an external sloc source");
458
459 if (CurrentLoadedOffset < TotalSize ||
460 CurrentLoadedOffset - TotalSize < NextLocalOffset) {
461 return std::make_pair(0, 0);
462 }
463 LoadedSLocEntryTable.resize(LoadedSLocEntryTable.size() + NumSLocEntries);
464 SLocEntryLoaded.resize(LoadedSLocEntryTable.size());
465 SLocEntryOffsetLoaded.resize(LoadedSLocEntryTable.size());
466 CurrentLoadedOffset -= TotalSize;
467 updateSlocUsageStats();
468 int BaseID = -int(LoadedSLocEntryTable.size()) - 1;
469 LoadedSLocEntryAllocBegin.push_back(FileID::get(BaseID));
470 return std::make_pair(BaseID, CurrentLoadedOffset);
471}
472
473
474
475llvm::MemoryBufferRef SourceManager::getFakeBufferForRecovery() const {
476 if (!FakeBufferForRecovery)
477 FakeBufferForRecovery =
478 llvm::MemoryBuffer::getMemBuffer("<<>");
479
480 return *FakeBufferForRecovery;
481}
482
483
484
486 if (!FakeContentCacheForRecovery) {
487 FakeContentCacheForRecovery = std::make_uniqueSrcMgr::ContentCache();
488 FakeContentCacheForRecovery->setUnownedBuffer(getFakeBufferForRecovery());
489 }
490 return *FakeContentCacheForRecovery;
491}
492
493
494
495FileID SourceManager::getPreviousFileID(FileID FID) const {
498
499 int ID = FID.ID;
500 if (ID == -1)
502
503 if (ID > 0) {
504 if (ID-1 == 0)
506 } else if (unsigned(-(ID-1) - 2) >= LoadedSLocEntryTable.size()) {
508 }
509
510 return FileID::get(ID-1);
511}
512
513
514
515FileID SourceManager::getNextFileID(FileID FID) const {
518
519 int ID = FID.ID;
520 if (ID > 0) {
523 } else if (ID+1 >= -1) {
525 }
526
527 return FileID::get(ID+1);
528}
529
530
531
532
533
534
535
539 int LoadedID,
543
544
545
548
549 return createFileIDImpl(IR, SourceFile.getName(), IncludePos, FileCharacter,
550 LoadedID, LoadedOffset);
551}
552
553
554
555
556
559 int LoadedID,
562 StringRef Name = Buffer->getBufferIdentifier();
563 return createFileIDImpl(createMemBufferContentCache(std::move(Buffer)), Name,
564 IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
565}
566
567
568
569
570
573 int LoadedID,
576 return createFileID(llvm::MemoryBuffer::getMemBuffer(Buffer), FileCharacter,
577 LoadedID, LoadedOffset, IncludeLoc);
578}
579
580
581
587 FileCharacter);
588}
589
590
592#ifdef __MVS__
593 llvm::ErrorOr NeedConversion =
594 llvm::needzOSConversion(Filename.str().c_str());
595 return NeedConversion && *NeedConversion;
596#else
597 return false;
598#endif
599}
600
601
602
603
607 int LoadedID,
609 if (LoadedID < 0) {
610 assert(LoadedID != -1 && "Loading sentinel FileID");
611 unsigned Index = unsigned(-LoadedID) - 2;
612 assert(Index < LoadedSLocEntryTable.size() && "FileID out of range");
613 assert(!SLocEntryLoaded[Index] && "FileID already loaded");
616 SLocEntryLoaded[Index] = SLocEntryOffsetLoaded[Index] = true;
617 return FileID::get(LoadedID);
618 }
619 unsigned FileSize = File.getSize();
621 if (NeedConversion) {
622
623
624 if (std::optionalllvm::MemoryBufferRef Buffer =
626 unsigned BufSize = Buffer->getBufferSize();
627 if (BufSize > FileSize) {
628 if (File.ContentsEntry.has_value())
629 File.ContentsEntry->updateFileEntryBufferSize(BufSize);
630 FileSize = BufSize;
631 }
632 }
633 }
634 if (!(NextLocalOffset + FileSize + 1 > NextLocalOffset &&
635 NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset)) {
636 Diag.Report(IncludePos, diag::err_sloc_space_too_large);
639 }
640 LocalSLocEntryTable.push_back(
643
644
645 NextLocalOffset += FileSize + 1;
646 updateSlocUsageStats();
647
648
649
650 FileID FID = FileID::get(LocalSLocEntryTable.size()-1);
651 return LastFileIDLookup = FID;
652}
653
657 ExpansionLoc);
658 return createExpansionLocImpl(Info, Length);
659}
660
664 bool ExpansionIsTokenRange, int LoadedID,
667 SpellingLoc, ExpansionLocStart, ExpansionLocEnd, ExpansionIsTokenRange);
668 return createExpansionLocImpl(Info, Length, LoadedID, LoadedOffset);
669}
670
675 "token spans multiple files");
676 return createExpansionLocImpl(
678 TokenEnd.getOffset() - TokenStart.getOffset());
679}
680
682SourceManager::createExpansionLocImpl(const ExpansionInfo &Info,
683 unsigned Length, int LoadedID,
685 if (LoadedID < 0) {
686 assert(LoadedID != -1 && "Loading sentinel FileID");
687 unsigned Index = unsigned(-LoadedID) - 2;
688 assert(Index < LoadedSLocEntryTable.size() && "FileID out of range");
689 assert(!SLocEntryLoaded[Index] && "FileID already loaded");
690 LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset, Info);
691 SLocEntryLoaded[Index] = SLocEntryOffsetLoaded[Index] = true;
692 return SourceLocation::getMacroLoc(LoadedOffset);
693 }
694 LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, Info));
695 if (NextLocalOffset + Length + 1 <= NextLocalOffset ||
696 NextLocalOffset + Length + 1 > CurrentLoadedOffset) {
697 Diag.Report(diag::err_sloc_space_too_large);
698
699
700
701
702
703 llvm::report_fatal_error("ran out of source locations");
704 }
705
706 NextLocalOffset += Length + 1;
707 updateSlocUsageStats();
708 return SourceLocation::getMacroLoc(NextLocalOffset - (Length + 1));
709}
710
711std::optionalllvm::MemoryBufferRef
715}
716
718 FileEntryRef SourceFile, std::unique_ptrllvm::MemoryBuffer Buffer) {
720
723
724 getOverriddenFilesInfo().OverriddenFilesWithBuffer.insert(SourceFile);
725}
726
730 "Different sizes, use the FileManager to create a virtual file with "
731 "the correct size");
732 assert(FileInfos.find_as(SourceFile) == FileInfos.end() &&
733 "This function should be called at the initialization stage, before "
734 "any parsing occurs.");
735
736 auto Pair = getOverriddenFilesInfo().OverriddenFiles.insert(
737 std::make_pair(SourceFile, NewFile));
738 if (!Pair.second)
739 Pair.first->second = NewFile;
740}
741
746
747
748 if (!BypassFile)
749 return std::nullopt;
750
751 (void)getOrCreateContentCache(*BypassFile);
752 return BypassFile;
753}
754
757}
758
759std::optional
762 if (Entry->getFile().getContentCache().OrigEntry)
763 return Entry->getFile().getName();
764 return std::nullopt;
765}
766
771 return B ? *B : "<<<<>>>>";
772}
773
774std::optional
778 return std::nullopt;
779}
780
783 if (auto B = Entry->getFile().getContentCache().getBufferOrNone(
785 return B->getBuffer();
786 return std::nullopt;
787}
788
789
790
791
792
793
794
795
796
797
799 if (!SLocOffset)
800 return FileID::get(0);
801
802
803
804 if (SLocOffset < NextLocalOffset)
805 return getFileIDLocal(SLocOffset);
806 return getFileIDLoaded(SLocOffset);
807}
808
809
810
811
812
814 assert(SLocOffset < NextLocalOffset && "Bad function choice");
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831 unsigned LessIndex = 0;
832
833 unsigned GreaterIndex = LocalSLocEntryTable.size();
834 if (LastFileIDLookup.ID >= 0) {
835
836 if (LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset)
837 LessIndex = LastFileIDLookup.ID;
838 else
839 GreaterIndex = LastFileIDLookup.ID;
840 }
841
842
843 unsigned NumProbes = 0;
844 while (true) {
845 --GreaterIndex;
846 assert(GreaterIndex < LocalSLocEntryTable.size());
847 if (LocalSLocEntryTable[GreaterIndex].getOffset() <= SLocOffset) {
848 FileID Res = FileID::get(int(GreaterIndex));
849
850 LastFileIDLookup = Res;
851 NumLinearScans += NumProbes+1;
852 return Res;
853 }
854 if (++NumProbes == 8)
855 break;
856 }
857
858 NumProbes = 0;
859 while (true) {
860 unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex;
863
864 ++NumProbes;
865
866
867
868 if (MidOffset > SLocOffset) {
869 GreaterIndex = MiddleIndex;
870 continue;
871 }
872
873
874 if (MiddleIndex + 1 == LocalSLocEntryTable.size() ||
876 FileID Res = FileID::get(MiddleIndex);
877
878
879 LastFileIDLookup = Res;
880 NumBinaryProbes += NumProbes;
881 return Res;
882 }
883
884
885 LessIndex = MiddleIndex;
886 }
887}
888
889
890
891
892
894 if (SLocOffset < CurrentLoadedOffset) {
895 assert(0 && "Invalid SLocOffset or bad function choice");
897 }
898
899 return FileID::get(ExternalSLocEntries->getSLocEntryID(SLocOffset));
900}
901
904 do {
905
906
907
908
909
910
913
914 return Loc;
915}
916
918 do {
923 return Loc;
924}
925
927 do {
930 else
933 return Loc;
934}
935
936
937std::pair<FileID, unsigned>
938SourceManager::getDecomposedExpansionLocSlowCase(
940
943 unsigned Offset;
944 do {
945 Loc = E->getExpansion().getExpansionLocStart();
946
949 Offset = Loc.getOffset()-E->getOffset();
951
952 return std::make_pair(FID, Offset);
953}
954
955std::pair<FileID, unsigned>
956SourceManager::getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
957 unsigned Offset) const {
958
961 do {
962 Loc = E->getExpansion().getSpellingLoc();
964
967 Offset = Loc.getOffset()-E->getOffset();
969
970 return std::make_pair(FID, Offset);
971}
972
973
974
975
976
982}
983
984
987 return F->getName();
988 return StringRef();
989}
990
991
992
995 assert(Loc.isMacroID() && "Not a macro expansion loc!");
998}
999
1003 return Loc;
1004}
1005
1006
1007
1011
1013
1014
1015
1022 }
1023 return Res;
1024}
1025
1029
1033
1034 if (StartLoc)
1036 return true;
1037}
1038
1041
1045}
1046
1050
1052 if (DecompLoc.second > 0)
1053 return false;
1054
1059 return false;
1061
1063
1064
1065
1066 FileID PrevFID = getPreviousFileID(DecompLoc.first);
1070 return false;
1073 return false;
1074 }
1075 }
1076
1077 if (MacroBegin)
1078 *MacroBegin = ExpLoc;
1079 return true;
1080}
1081
1085
1089 return false;
1090
1095 return false;
1096
1098
1099
1100
1101 FileID NextFID = getNextFileID(FID);
1105 return false;
1109 return false;
1110 }
1111 }
1112
1113 if (MacroEnd)
1115 return true;
1116}
1117
1118
1119
1120
1121
1122
1123
1126
1127
1129
1130
1131 bool CharDataInvalid = false;
1133 if (CharDataInvalid || !Entry.isFile()) {
1136
1137 return "<<<>>>";
1138 }
1139 std::optionalllvm::MemoryBufferRef Buffer =
1144 return Buffer ? Buffer->getBufferStart() + LocInfo.second
1145 : "<<<>>>";
1146}
1147
1148
1149
1152 std::optionalllvm::MemoryBufferRef MemBuf = getBufferOrNone(FID);
1155
1156 if (!MemBuf)
1157 return 1;
1158
1159
1160 if (FilePos > MemBuf->getBufferSize()) {
1163 return 1;
1164 }
1165
1166 const char *Buf = MemBuf->getBufferStart();
1167
1168
1169 if (LastLineNoFileIDQuery == FID && LastLineNoContentCache->SourceLineCache &&
1170 LastLineNoResult < LastLineNoContentCache->SourceLineCache.size()) {
1171 const unsigned *SourceLineCache =
1173 unsigned LineStart = SourceLineCache[LastLineNoResult - 1];
1174 unsigned LineEnd = SourceLineCache[LastLineNoResult];
1175 if (FilePos >= LineStart && FilePos < LineEnd) {
1176
1177
1178
1179
1180 if (FilePos + 1 == LineEnd && FilePos > LineStart) {
1181 if (Buf[FilePos - 1] == '\r' || Buf[FilePos - 1] == '\n')
1182 --FilePos;
1183 }
1184 return FilePos - LineStart + 1;
1185 }
1186 }
1187
1188 unsigned LineStart = FilePos;
1189 while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
1190 --LineStart;
1191 return FilePos-LineStart+1;
1192}
1193
1194
1195
1196template
1201 return MyInvalid;
1202}
1203
1209}
1210
1216}
1217
1223}
1224
1225
1226
1227
1228
1229template
1231 unsigned char n) {
1232 return ((x - ~static_cast<T>(0) / 255 * (n + 1)) & ~x &
1233 ((x & ~static_cast<T>(0) / 255 * 127) +
1234 (~static_cast<T>(0) / 255 * (127 - (m - 1))))) &
1235 ~static_cast(0) / 255 * 128;
1236}
1237
1239 llvm::BumpPtrAllocator &Alloc) {
1240
1241
1242
1244
1245
1246 LineOffsets.push_back(0);
1247
1248 const unsigned char *Start = (const unsigned char *)Buffer.getBufferStart();
1249 const unsigned char *End = (const unsigned char *)Buffer.getBufferEnd();
1250 const unsigned char *Buf = Start;
1251
1252 uint64_t Word;
1253
1254
1255
1256 if ((unsigned long)(End - Start) > sizeof(Word)) {
1257 do {
1258 Word = llvm::support::endian::read64(Buf, llvm::endianness::little);
1259
1261 if (!Mask) {
1262 Buf += sizeof(Word);
1263 continue;
1264 }
1265
1266
1267
1268
1269
1270 unsigned N = llvm::countr_zero(Mask) - 7;
1271 Word >>= N;
1272 Buf += N / 8 + 1;
1273 unsigned char Byte = Word;
1274 switch (Byte) {
1275 case '\r':
1276
1277 if (*Buf == '\n') {
1278 ++Buf;
1279 }
1280 [[fallthrough]];
1281 case '\n':
1282 LineOffsets.push_back(Buf - Start);
1283 };
1284 } while (Buf < End - sizeof(Word) - 1);
1285 }
1286
1287
1288 while (Buf < End) {
1289 if (*Buf == '\n') {
1290 LineOffsets.push_back(Buf - Start + 1);
1291 } else if (*Buf == '\r') {
1292
1293 if (Buf + 1 < End && Buf[1] == '\n') {
1294 ++Buf;
1295 }
1296 LineOffsets.push_back(Buf - Start + 1);
1297 }
1298 ++Buf;
1299 }
1300
1302}
1303
1305 llvm::BumpPtrAllocator &Alloc)
1306 : Storage(Alloc.Allocate<unsigned>(LineOffsets.size() + 1)) {
1307 Storage[0] = LineOffsets.size();
1308 std::copy(LineOffsets.begin(), LineOffsets.end(), Storage + 1);
1309}
1310
1311
1312
1313
1314
1320 return 1;
1321 }
1322
1324 if (LastLineNoFileIDQuery == FID)
1325 Content = LastLineNoContentCache;
1326 else {
1327 bool MyInvalid = false;
1328 const SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
1329 if (MyInvalid || !Entry.isFile()) {
1332 return 1;
1333 }
1334
1336 }
1337
1338
1339
1341 std::optionalllvm::MemoryBufferRef Buffer =
1345 if (!Buffer)
1346 return 1;
1347
1352
1353
1354
1356 const unsigned *SourceLineCacheStart = SourceLineCache;
1357 const unsigned *SourceLineCacheEnd = Content->SourceLineCache.end();
1358
1359 unsigned QueriedFilePos = FilePos+1;
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374 if (LastLineNoFileIDQuery == FID) {
1375 if (QueriedFilePos >= LastLineNoFilePos) {
1376
1377 SourceLineCache = SourceLineCache+LastLineNoResult-1;
1378
1379
1380
1381
1382
1383 if (SourceLineCache+5 < SourceLineCacheEnd) {
1384 if (SourceLineCache[5] > QueriedFilePos)
1385 SourceLineCacheEnd = SourceLineCache+5;
1386 else if (SourceLineCache+10 < SourceLineCacheEnd) {
1387 if (SourceLineCache[10] > QueriedFilePos)
1388 SourceLineCacheEnd = SourceLineCache+10;
1389 else if (SourceLineCache+20 < SourceLineCacheEnd) {
1390 if (SourceLineCache[20] > QueriedFilePos)
1391 SourceLineCacheEnd = SourceLineCache+20;
1392 }
1393 }
1394 }
1395 } else {
1396 if (LastLineNoResult < Content->SourceLineCache.size())
1397 SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1;
1398 }
1399 }
1400
1401 const unsigned *Pos =
1402 std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos);
1403 unsigned LineNo = Pos-SourceLineCacheStart;
1404
1405 LastLineNoFileIDQuery = FID;
1406 LastLineNoContentCache = Content;
1407 LastLineNoFilePos = QueriedFilePos;
1408 LastLineNoResult = LineNo;
1409 return LineNo;
1410}
1411
1415 std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
1416 return getLineNumber(LocInfo.first, LocInfo.second);
1417}
1421 std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
1422 return getLineNumber(LocInfo.first, LocInfo.second);
1423}
1429}
1430
1431
1432
1433
1434
1435
1436
1437
1438
1441 assert(Loc.isValid() && "Can't get file characteristic of invalid loc!");
1442 std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
1443 const SLocEntry *SEntry = getSLocEntryForFile(LocInfo.first);
1444 if (!SEntry)
1446
1448
1449
1450
1453
1454 assert(LineTable && "Can't have linetable entries without a LineTable!");
1455
1457 LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second);
1458
1459
1460 if (!Entry)
1462
1464}
1465
1466
1467
1468
1472
1473 auto B = getBufferOrNone(getFileID(Loc));
1476 return B ? B->getBufferIdentifier() : "";
1477}
1478
1479
1480
1481
1482
1483
1484
1485
1487 bool UseLineDirectives) const {
1489
1490
1491 std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
1492
1494 const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
1497
1500
1501
1502
1503
1504 FileID FID = LocInfo.first;
1506 if (C->OrigEntry)
1507 Filename = C->OrigEntry->getName();
1508 else if (auto Buffer = C->getBufferOrNone(Diag, getFileManager()))
1509 Filename = Buffer->getBufferIdentifier();
1510
1511 unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid);
1514 unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second, &Invalid);
1517
1519
1520
1521
1523 assert(LineTable && "Can't have linetable entries without a LineTable!");
1524
1526 LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second)) {
1527
1528 if (Entry->FilenameID != -1) {
1529 Filename = LineTable->getFilename(Entry->FilenameID);
1530
1531
1532 FID = FileID::get(0);
1533 }
1534
1535
1536
1537
1538
1539 unsigned MarkerLineNo = getLineNumber(LocInfo.first, Entry->FileOffset);
1540 LineNo = Entry->LineNo + (LineNo-MarkerLineNo-1);
1541
1542
1543
1544
1545 if (Entry->IncludeOffset) {
1546 IncludeLoc = getLocForStartOfFile(LocInfo.first);
1547 IncludeLoc = IncludeLoc.getLocWithOffset(Entry->IncludeOffset);
1548 }
1549 }
1550 }
1551
1553}
1554
1555
1556
1557
1558
1559
1560
1561
1564
1565
1566 std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
1567
1568 const SLocEntry *Entry = getSLocEntryForFile(LocInfo.first);
1569 if (!Entry)
1570 return false;
1571
1573
1574
1577 LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second))
1578 if (Entry->IncludeOffset)
1579 return false;
1580
1582}
1583
1584
1589 return 0;
1590
1591 int ID = FID.ID;
1593 if ((ID > 0 && unsigned(ID+1) == local_sloc_entry_size()))
1594 NextOffset = getNextLocalOffset();
1595 else if (ID+1 == -1)
1596 NextOffset = MaxLoadedOffset;
1597 else
1598 NextOffset = getSLocEntry(FileID::get(ID+1)).getOffset();
1599
1600 return NextOffset - Entry.getOffset() - 1;
1601}
1602
1603
1604
1605
1606
1607
1608
1609
1610
1612 unsigned Line,
1613 unsigned Col) const {
1614 assert(SourceFile && "Null source file!");
1615 assert(Line && Col && "Line and column should start from 1!");
1616
1617 FileID FirstFID = translateFile(SourceFile);
1618 return translateLineCol(FirstFID, Line, Col);
1619}
1620
1621
1622
1623
1624
1626 assert(SourceFile && "Null source file!");
1627
1628
1629
1630 if (MainFileID.isValid()) {
1632 const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid);
1635
1636 if (MainSLoc.isFile()) {
1638 return MainFileID;
1639 }
1640 }
1641
1642
1643
1644 for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) {
1645 const SLocEntry &SLoc = getLocalSLocEntry(I);
1646 if (SLoc.isFile() &&
1648 return FileID::get(I);
1649 }
1650
1651
1652 for (unsigned I = 0, N = loaded_sloc_entry_size(); I != N; ++I) {
1653 const SLocEntry &SLoc = getLoadedSLocEntry(I);
1654 if (SLoc.isFile() &&
1656 return FileID::get(-int(I) - 2);
1657 }
1658
1660}
1661
1662
1663
1665 unsigned Line,
1666 unsigned Col) const {
1667
1668
1669 assert(Line && Col && "Line and column should start from 1!");
1670
1673
1678
1679 if (!Entry.isFile())
1681
1683
1684 if (Line == 1 && Col == 1)
1685 return FileLoc;
1686
1688
1689
1690
1691 std::optionalllvm::MemoryBufferRef Buffer =
1693 if (!Buffer)
1698
1700 unsigned Size = Buffer->getBufferSize();
1701 if (Size > 0)
1702 --Size;
1704 }
1705
1707 const char *Buf = Buffer->getBufferStart() + FilePos;
1708 unsigned BufLength = Buffer->getBufferSize() - FilePos;
1709 if (BufLength == 0)
1711
1712 unsigned i = 0;
1713
1714
1715 while (i < BufLength-1 && i < Col-1 && Buf[i] != '\n' && Buf[i] != '\r')
1716 ++i;
1718}
1719
1720
1721
1722
1723
1724
1725
1726
1727void SourceManager::computeMacroArgsCache(MacroArgsMap &MacroArgsCache,
1730
1731
1732 MacroArgsCache.insert(std::make_pair(0, SourceLocation()));
1733
1734 int ID = FID.ID;
1735 while (true) {
1736 ++ID;
1737
1738 if (ID > 0) {
1739 if (unsigned(ID) >= local_sloc_entry_size())
1740 return;
1741 } else if (ID == -1) {
1742 return;
1743 }
1744
1748 return;
1749 if (Entry.isFile()) {
1753 continue;
1754
1756 bool IncludedInFID =
1757 (IncludeLoc.isValid() && isInFileID(IncludeLoc, FID)) ||
1758
1759
1760
1761 (FID == MainFileID && Entry.getFile().getName() == "");
1762 if (IncludedInFID) {
1763
1764
1765 if (Entry.getFile().NumCreatedFIDs)
1766 ID += Entry.getFile().NumCreatedFIDs - 1 ;
1767 continue;
1768 }
1769
1770
1771 if (IncludeLoc.isValid())
1772 return;
1773 continue;
1774 }
1775
1777
1780 return;
1781 }
1782
1784 continue;
1785
1786 associateFileChunkWithMacroArgExp(MacroArgsCache, FID,
1788 SourceLocation::getMacroLoc(Entry.getOffset()),
1789 getFileIDSize(FileID::get(ID)));
1790 }
1791}
1792
1793void SourceManager::associateFileChunkWithMacroArgExp(
1794 MacroArgsMap &MacroArgsCache,
1798 unsigned ExpansionLength) const {
1802
1803
1804
1805
1806
1807
1808 FileID SpellFID;
1809 unsigned SpellRelativeOffs;
1810 std::tie(SpellFID, SpellRelativeOffs) = getDecomposedLoc(SpellLoc);
1811 while (true) {
1812 const SLocEntry &Entry = getSLocEntry(SpellFID);
1814 unsigned SpellFIDSize = getFileIDSize(SpellFID);
1818 unsigned CurrSpellLength;
1819 if (SpellFIDEndOffs < SpellEndOffs)
1820 CurrSpellLength = SpellFIDSize - SpellRelativeOffs;
1821 else
1822 CurrSpellLength = ExpansionLength;
1823 associateFileChunkWithMacroArgExp(MacroArgsCache, FID,
1825 ExpansionLoc, CurrSpellLength);
1826 }
1827
1828 if (SpellFIDEndOffs >= SpellEndOffs)
1829 return;
1830
1831
1832 unsigned advance = SpellFIDSize - SpellRelativeOffs + 1;
1834 ExpansionLength -= advance;
1835 ++SpellFID.ID;
1836 SpellRelativeOffs = 0;
1837 }
1838 }
1839
1840 assert(SpellLoc.isFileID());
1841
1842 unsigned BeginOffs;
1843 if (!isInFileID(SpellLoc, FID, &BeginOffs))
1844 return;
1845
1846 unsigned EndOffs = BeginOffs + ExpansionLength;
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865 MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs);
1866 --I;
1868 MacroArgsCache[BeginOffs] = ExpansionLoc;
1869 MacroArgsCache[EndOffs] = EndOffsMappedLoc;
1870}
1871
1872void SourceManager::updateSlocUsageStats() const {
1874 NextLocalOffset + (MaxLoadedOffset - CurrentLoadedOffset);
1875 MaxUsedSLocBytes.updateMax(UsedBytes);
1876}
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1890 return Loc;
1891
1893 unsigned Offset;
1894 std::tie(FID, Offset) = getDecomposedLoc(Loc);
1896 return Loc;
1897
1898 std::unique_ptr &MacroArgsCache = MacroArgsCacheMap[FID];
1899 if (!MacroArgsCache) {
1900 MacroArgsCache = std::make_unique();
1901 computeMacroArgsCache(*MacroArgsCache, FID);
1902 }
1903
1904 assert(!MacroArgsCache->empty());
1905 MacroArgsMap::iterator I = MacroArgsCache->upper_bound(Offset);
1906
1907
1908 if (I == MacroArgsCache->begin())
1909 return Loc;
1910
1911 --I;
1912
1915 if (MacroArgExpandedLoc.isValid())
1916 return MacroArgExpandedLoc.getLocWithOffset(Offset - MacroArgBeginOffs);
1917
1918 return Loc;
1919}
1920
1921std::pair<FileID, unsigned>
1924 return std::make_pair(FileID(), 0);
1925
1926
1927
1928 using DecompTy = std::pair<FileID, unsigned>;
1929 auto InsertOp = IncludedLocMap.try_emplace(FID);
1930 DecompTy &DecompLoc = InsertOp.first->second;
1931 if (!InsertOp.second)
1932 return DecompLoc;
1933
1940 else
1942 }
1943
1945 DecompLoc = getDecomposedLoc(UpperLoc);
1946
1947 return DecompLoc;
1948}
1949
1951 assert(isLoadedSourceLocation(Loc) &&
1952 "Must be a source location in a loaded PCH/Module file");
1953
1954 auto [FID, Ignore] = getDecomposedLoc(Loc);
1955
1956
1957
1958
1959 const FileID *FirstFID =
1960 llvm::lower_bound(LoadedSLocEntryAllocBegin, FID, std::greater{});
1961
1962 assert(FirstFID &&
1963 "The failure to find the first FileID of a "
1964 "loaded AST from a loaded source location was unexpected.");
1965 return *FirstFID;
1966}
1967
1969 const std::pair<FileID, unsigned> &LOffs,
1970 const std::pair<FileID, unsigned> &ROffs) const {
1971
1972 if (isLoadedFileID(LOffs.first) != isLoadedFileID(ROffs.first))
1973 return false;
1974
1975 if (isLoadedFileID(LOffs.first) && isLoadedFileID(ROffs.first)) {
1976 auto FindSLocEntryAlloc = [this](FileID FID) {
1977
1978
1979 return llvm::lower_bound(LoadedSLocEntryAllocBegin, FID,
1980 std::greater{});
1981 };
1982
1983
1984 if (FindSLocEntryAlloc(LOffs.first) != FindSLocEntryAlloc(ROffs.first))
1985 return false;
1986 }
1987
1988 return true;
1989}
1990
1991
1992
1993
1994
1995static bool
1998 std::pair<FileID, unsigned> UpperLoc = SM.getDecomposedIncludedLoc(Loc.first);
1999 if (UpperLoc.first.isInvalid() ||
2000 .isInTheSameTranslationUnitImpl(UpperLoc, Loc))
2001 return true;
2002
2003 Loc = UpperLoc;
2004 return false;
2005}
2006
2007
2008
2010 FileID RFID) const {
2011
2012
2013
2014
2015 enum { MagicCacheSize = 300 };
2016 IsBeforeInTUCacheKey Key(LFID, RFID);
2017
2018
2019
2020
2021
2022 if (IBTUCache.size() < MagicCacheSize)
2023 return IBTUCache.try_emplace(Key, LFID, RFID).first->second;
2024
2025
2026 InBeforeInTUCache::iterator I = IBTUCache.find(Key);
2027 if (I != IBTUCache.end())
2028 return I->second;
2029
2030
2031 IBTUCacheOverflow.setQueryFIDs(LFID, RFID);
2032 return IBTUCacheOverflow;
2033}
2034
2035
2036
2037
2040 assert(LHS.isValid() && RHS.isValid() && "Passed invalid source location!");
2041 if (LHS == RHS)
2042 return false;
2043
2044 std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS);
2045 std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS);
2046
2047
2048
2049
2050 if (LOffs.first.isInvalid() || ROffs.first.isInvalid())
2051 return LOffs.first.isInvalid() && !ROffs.first.isInvalid();
2052
2053 std::pair<bool, bool> InSameTU = isInTheSameTranslationUnit(LOffs, ROffs);
2054 if (InSameTU.first)
2055 return InSameTU.second;
2056
2057 return LOffs.first < ROffs.first;
2058}
2059
2061 std::pair<FileID, unsigned> &LOffs,
2062 std::pair<FileID, unsigned> &ROffs) const {
2063
2064 if (!isInTheSameTranslationUnitImpl(LOffs, ROffs))
2065 return std::make_pair(false, false);
2066
2067
2068 if (LOffs.first == ROffs.first)
2069 return std::make_pair(true, LOffs.second < ROffs.second);
2070
2071
2072
2074 getInBeforeInTUCache(LOffs.first, ROffs.first);
2075
2076
2077
2079 return std::make_pair(
2080 true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second));
2081
2082
2083
2084
2085
2086
2087
2088 struct Entry {
2089 std::pair<FileID, unsigned> DecomposedLoc;
2090 FileID ChildFID;
2091 };
2092 llvm::SmallDenseMap<FileID, Entry, 16> LChain;
2093
2095 do {
2096 LChain.try_emplace(LOffs.first, Entry{LOffs, LChild});
2097
2098
2099 if (LOffs.first == ROffs.first)
2100 break;
2101 LChild = LOffs.first;
2103
2105 do {
2106 auto LIt = LChain.find(ROffs.first);
2107 if (LIt != LChain.end()) {
2108
2109 LOffs = LIt->second.DecomposedLoc;
2110 LChild = LIt->second.ChildFID;
2111
2112
2113
2114
2115
2116
2117
2118
2119 unsigned LChildID = LChild.ID;
2120 unsigned RChildID = RChild.ID;
2121 assert(((LOffs.second != ROffs.second) ||
2122 (LChildID == 0 || RChildID == 0) ||
2123 isInSameSLocAddrSpace(getComposedLoc(LChild, 0),
2124 getComposedLoc(RChild, 0), nullptr)) &&
2125 "Mixed local/loaded FileIDs with same include location?");
2126 IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second,
2127 LChildID < RChildID);
2128 return std::make_pair(
2129 true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second));
2130 }
2131 RChild = ROffs.first;
2133
2134
2135
2136
2137 StringRef LB = getBufferOrFake(LOffs.first).getBufferIdentifier();
2138 StringRef RB = getBufferOrFake(ROffs.first).getBufferIdentifier();
2139
2140 bool LIsBuiltins = LB == "";
2141 bool RIsBuiltins = RB == "";
2142
2143 if (LIsBuiltins || RIsBuiltins) {
2144 if (LIsBuiltins != RIsBuiltins)
2145 return std::make_pair(true, LIsBuiltins);
2146
2147
2148 return std::make_pair(true, LOffs.first < ROffs.first);
2149 }
2150
2151 bool LIsAsm = LB == "";
2152 bool RIsAsm = RB == "";
2153
2154 if (LIsAsm || RIsAsm) {
2155 if (LIsAsm != RIsAsm)
2156 return std::make_pair(true, RIsAsm);
2157 assert(LOffs.first == ROffs.first);
2158 return std::make_pair(true, false);
2159 }
2160
2161 bool LIsScratch = LB == "";
2162 bool RIsScratch = RB == "";
2163
2164 if (LIsScratch || RIsScratch) {
2165 if (LIsScratch != RIsScratch)
2166 return std::make_pair(true, LIsScratch);
2167 return std::make_pair(true, LOffs.second < ROffs.second);
2168 }
2169
2170 llvm_unreachable("Unsortable locations found");
2171}
2172
2174 llvm::errs() << "\n*** Source Manager Stats:\n";
2175 llvm::errs() << FileInfos.size() << " files mapped, " << MemBufferInfos.size()
2176 << " mem buffers mapped.\n";
2177 llvm::errs() << LocalSLocEntryTable.size() << " local SLocEntries allocated ("
2178 << llvm::capacity_in_bytes(LocalSLocEntryTable)
2179 << " bytes of capacity), " << NextLocalOffset
2180 << "B of SLoc address space used.\n";
2181 llvm::errs() << LoadedSLocEntryTable.size()
2182 << " loaded SLocEntries allocated ("
2183 << llvm::capacity_in_bytes(LoadedSLocEntryTable)
2184 << " bytes of capacity), "
2185 << MaxLoadedOffset - CurrentLoadedOffset
2186 << "B of SLoc address space used.\n";
2187
2188 unsigned NumLineNumsComputed = 0;
2189 unsigned NumFileBytesMapped = 0;
2190 for (fileinfo_iterator I = fileinfo_begin(), E = fileinfo_end(); I != E; ++I){
2191 NumLineNumsComputed += bool(I->second->SourceLineCache);
2192 NumFileBytesMapped += I->second->getSizeBytesMapped();
2193 }
2194 unsigned NumMacroArgsComputed = MacroArgsCacheMap.size();
2195
2196 llvm::errs() << NumFileBytesMapped << " bytes of files mapped, "
2197 << NumLineNumsComputed << " files with line #'s computed, "
2198 << NumMacroArgsComputed << " files with macro args computed.\n";
2199 llvm::errs() << "FileID scans: " << NumLinearScans << " linear, "
2200 << NumBinaryProbes << " binary.\n";
2201}
2202
2204 llvm::raw_ostream &out = llvm::errs();
2205
2206 auto DumpSLocEntry = [&](int ID, const SrcMgr::SLocEntry &Entry,
2207 std::optionalSourceLocation::UIntTy NextStart) {
2208 out << "SLocEntry <FileID " << ID << "> " << (Entry.isFile() ? "file" : "expansion")
2209 << " <SourceLocation " << Entry.getOffset() << ":";
2210 if (NextStart)
2211 out << *NextStart << ">\n";
2212 else
2213 out << "???\?>\n";
2214 if (Entry.isFile()) {
2215 auto &FI = Entry.getFile();
2216 if (FI.NumCreatedFIDs)
2217 out << " covers <FileID " << ID << ":" << int(ID + FI.NumCreatedFIDs)
2218 << ">\n";
2219 if (FI.getIncludeLoc().isValid())
2220 out << " included from " << FI.getIncludeLoc().getOffset() << "\n";
2221 auto &CC = FI.getContentCache();
2222 out << " for " << (CC.OrigEntry ? CC.OrigEntry->getName() : "")
2223 << "\n";
2224 if (CC.BufferOverridden)
2225 out << " contents overridden\n";
2226 if (CC.ContentsEntry != CC.OrigEntry) {
2227 out << " contents from "
2228 << (CC.ContentsEntry ? CC.ContentsEntry->getName() : "")
2229 << "\n";
2230 }
2231 } else {
2232 auto &EI = Entry.getExpansion();
2233 out << " spelling from " << EI.getSpellingLoc().getOffset() << "\n";
2234 out << " macro " << (EI.isMacroArgExpansion() ? "arg" : "body")
2235 << " range <" << EI.getExpansionLocStart().getOffset() << ":"
2236 << EI.getExpansionLocEnd().getOffset() << ">\n";
2237 }
2238 };
2239
2240
2241 for (unsigned ID = 0, NumIDs = LocalSLocEntryTable.size(); ID != NumIDs; ++ID) {
2242 DumpSLocEntry(ID, LocalSLocEntryTable[ID],
2243 ID == NumIDs - 1 ? NextLocalOffset
2244 : LocalSLocEntryTable[ID + 1].getOffset());
2245 }
2246
2247 std::optionalSourceLocation::UIntTy NextStart;
2248 for (unsigned Index = 0; Index != LoadedSLocEntryTable.size(); ++Index) {
2249 int ID = -(int)Index - 2;
2250 if (SLocEntryLoaded[Index]) {
2251 DumpSLocEntry(ID, LoadedSLocEntryTable[Index], NextStart);
2252 NextStart = LoadedSLocEntryTable[Index].getOffset();
2253 } else {
2254 NextStart = std::nullopt;
2255 }
2256 }
2257}
2258
2261 struct Info {
2262
2264
2265 unsigned Inclusions = 0;
2266
2267 uint64_t DirectSize = 0;
2268
2269 uint64_t TotalSize = 0;
2270 };
2271 using UsageMap = llvm::MapVector<const FileEntry*, Info>;
2272
2273 UsageMap Usage;
2274 uint64_t CountedSize = 0;
2275
2276 auto AddUsageForFileID = [&](FileID ID) {
2277
2278
2279 unsigned Size = getFileIDSize(ID) + 1;
2280
2281
2282
2283 SourceLocation FileStart = getFileLoc(getComposedLoc(ID, 0));
2284 FileID FileLocID = getFileID(FileStart);
2285 const FileEntry *Entry = getFileEntryForID(FileLocID);
2286
2287 Info &EntryInfo = Usage[Entry];
2288 if (EntryInfo.Loc.isInvalid())
2289 EntryInfo.Loc = FileStart;
2290 if (ID == FileLocID) {
2291 ++EntryInfo.Inclusions;
2292 EntryInfo.DirectSize += Size;
2293 }
2294 EntryInfo.TotalSize += Size;
2295 CountedSize += Size;
2296 };
2297
2298
2299 for (size_t Index = 0; Index != LoadedSLocEntryTable.size(); ++Index) {
2300 AddUsageForFileID(FileID::get(-2 - Index));
2301 }
2302
2303 for (size_t Index = 0; Index != LocalSLocEntryTable.size(); ++Index) {
2304 AddUsageForFileID(FileID::get(Index));
2305 }
2306
2307
2308
2309 auto SortedUsage = Usage.takeVector();
2310 auto Cmp = [](const UsageMap::value_type &A, const UsageMap::value_type &B) {
2311 return A.second.TotalSize > B.second.TotalSize ||
2312 (A.second.TotalSize == B.second.TotalSize &&
2313 A.second.Loc < B.second.Loc);
2314 };
2315 auto SortedEnd = SortedUsage.end();
2316 if (MaxNotes && SortedUsage.size() > *MaxNotes) {
2317 SortedEnd = SortedUsage.begin() + *MaxNotes;
2318 std::nth_element(SortedUsage.begin(), SortedEnd, SortedUsage.end(), Cmp);
2319 }
2320 std::sort(SortedUsage.begin(), SortedEnd, Cmp);
2321
2322
2323 uint64_t LocalUsage = NextLocalOffset;
2324 uint64_t LoadedUsage = MaxLoadedOffset - CurrentLoadedOffset;
2325 int UsagePercent = static_cast<int>(100.0 * double(LocalUsage + LoadedUsage) /
2326 MaxLoadedOffset);
2327 Diag.Report(diag::note_total_sloc_usage)
2328 << LocalUsage << LoadedUsage << (LocalUsage + LoadedUsage)
2329 << UsagePercent;
2330
2331
2332 uint64_t ReportedSize = 0;
2333 for (auto &[Entry, FileInfo] :
2334 llvm::make_range(SortedUsage.begin(), SortedEnd)) {
2335 Diag.Report(FileInfo.Loc, diag::note_file_sloc_usage)
2338 ReportedSize += FileInfo.TotalSize;
2339 }
2340
2341
2342 if (ReportedSize != CountedSize) {
2343 Diag.Report(diag::note_file_misc_sloc_usage)
2344 << (SortedUsage.end() - SortedEnd) << CountedSize - ReportedSize;
2345 }
2346}
2347
2349
2350
2351
2353 size_t malloc_bytes = 0;
2354 size_t mmap_bytes = 0;
2355
2356 for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i)
2357 if (size_t sized_mapped = MemBufferInfos[i]->getSizeBytesMapped())
2358 switch (MemBufferInfos[i]->getMemoryBufferKind()) {
2359 case llvm::MemoryBuffer::MemoryBuffer_MMap:
2360 mmap_bytes += sized_mapped;
2361 break;
2362 case llvm::MemoryBuffer::MemoryBuffer_Malloc:
2363 malloc_bytes += sized_mapped;
2364 break;
2365 }
2366
2368}
2369
2371 size_t size = llvm::capacity_in_bytes(MemBufferInfos) +
2372 llvm::capacity_in_bytes(LocalSLocEntryTable) +
2373 llvm::capacity_in_bytes(LoadedSLocEntryTable) +
2374 llvm::capacity_in_bytes(SLocEntryLoaded) +
2375 llvm::capacity_in_bytes(FileInfos);
2376
2377 if (OverriddenFilesInfo)
2378 size += llvm::capacity_in_bytes(OverriddenFilesInfo->OverriddenFiles);
2379
2380 return size;
2381}
2382
2384 StringRef Content) {
2385
2386
2388 new llvm::vfs::InMemoryFileSystem);
2389 InMemoryFileSystem->addFile(
2391 llvm::MemoryBuffer::getMemBuffer(Content, FileName,
2392 false));
2393
2394
2395 FileMgr =
2396 std::make_unique(FileSystemOptions(), InMemoryFileSystem);
2397
2398
2399 Diagnostics = std::make_unique(
2402 SourceMgr = std::make_unique(*Diagnostics, *FileMgr);
2406 assert(ID.isValid());
2407 SourceMgr->setMainFileID(ID);
2408}
Defines the Diagnostic-related interfaces.
Defines the clang::FileManager interface and associated types.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
static ParseState advance(ParseState S, size_t N)
Defines the clang::SourceLocation class and associated facilities.
Defines implementation details of the clang::SourceManager class.
static constexpr T likelyhasbetween(T x, unsigned char m, unsigned char n)
static bool MoveUpTranslationUnitIncludeHierarchy(std::pair< FileID, unsigned > &Loc, const SourceManager &SM)
Given a decomposed source location, move it up the include/expansion stack to the parent source locat...
static bool isInvalid(LocType Loc, bool *Invalid)
STATISTIC(MaxUsedSLocBytes, "Maximum number of bytes used by source locations " "(both loaded and local).")
bool needConversion(StringRef Filename)
Helper function to determine if an input file requires conversion.
Defines the SourceManager interface.
Represents a character-granular source range.
void setEnd(SourceLocation e)
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
void setBegin(SourceLocation b)
SourceLocation getEnd() const
SourceLocation getBegin() const
void setTokenRange(bool TR)
Used for handling and querying diagnostic IDs.
Options for controlling the compiler diagnostics engine.
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
void setSourceManager(SourceManager *SrcMgr)
virtual int getSLocEntryID(SourceLocation::UIntTy SLocOffset)=0
Get the index ID for the loaded SourceLocation offset.
virtual ~ExternalSLocEntrySource()
virtual bool ReadSLocEntry(int ID)=0
Read the source location entry with index ID, which will always be less than -1.
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
StringRef getName() const
The name of this FileEntry.
Cached information about one file (either on disk or in the virtual file system).
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Implements support for file system lookup, file system caching, and directory search management.
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(FileEntryRef Entry, bool isVolatile=false, bool RequiresNullTerminator=true, std::optional< int64_t > MaybeLimit=std::nullopt, bool IsText=true)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
OptionalFileEntryRef getBypassFile(FileEntryRef VFE)
Retrieve a FileEntry that bypasses VFE, which is expected to be a virtual file entry,...
Keeps track of options that affect how file operations are performed.
Holds the cache used by isBeforeInTranslationUnit.
void setCommonLoc(FileID commonFID, unsigned lCommonOffset, unsigned rCommonOffset, bool LParentBeforeRParent)
bool getCachedResult(unsigned LOffset, unsigned ROffset) const
If the cache is valid, compute the result given the specified offsets in the LHS/RHS FileID's.
bool isCacheValid() const
Return true if the currently cached values match up with the specified LHS/RHS query.
Used to hold and unique data used to represent #line information.
const LineEntry * FindNearestLineEntry(FileID FID, unsigned Offset)
Find the line entry nearest to FID that is before it.
unsigned getLineTableFilenameID(StringRef Str)
void AddEntry(FileID FID, const std::vector< LineEntry > &Entries)
Add a new line entry that has already been encoded into the internal representation of the line table...
void AddLineNote(FileID FID, unsigned Offset, unsigned LineNo, int FilenameID, unsigned EntryExit, SrcMgr::CharacteristicKind FileKind)
Add a line note to the line table that indicates that there is a #line or GNU line marker at the spec...
Represents an unpacked "presumed" location which can be presented to the user.
unsigned getColumn() const
Return the presumed column number of this location.
unsigned getLine() const
Return the presumed line number of this location.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
SourceManagerForFile(StringRef FileName, StringRef Content)
Creates SourceManager and necessary dependencies (e.g.
This class handles loading and caching of source files into memory.
std::optional< StringRef > getNonBuiltinFilenameForID(FileID FID) const
Returns the filename for the provided FileID, unless it's a built-in buffer that's not represented by...
bool isMacroBodyExpansion(SourceLocation Loc) const
Tests whether the given source location represents the expansion of a macro body.
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
bool isAtEndOfImmediateMacroExpansion(SourceLocation Loc, SourceLocation *MacroEnd=nullptr) const
Returns true if the given MacroID location points at the character end of the immediate macro expansi...
unsigned getColumnNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Return the column # for the specified file position.
void noteSLocAddressSpaceUsage(DiagnosticsEngine &Diag, std::optional< unsigned > MaxNotes=32) const
bool isInMainFile(SourceLocation Loc) const
Returns whether the PresumedLoc for a given SourceLocation is in the main file.
void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID, bool IsFileEntry, bool IsFileExit, SrcMgr::CharacteristicKind FileKind)
Add a line note to the line table for the FileID and offset specified by Loc.
SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr, bool UserFilesAreVolatile=false)
SourceLocation createTokenSplitLoc(SourceLocation SpellingLoc, SourceLocation TokenStart, SourceLocation TokenEnd)
Return a new SourceLocation that encodes that the token starting at TokenStart ends prematurely at To...
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.
MemoryBufferSizes getMemoryBufferSizes() const
Return the amount of memory used by memory buffers, breaking down by heap-backed versus mmap'ed memor...
void setFileIsTransient(FileEntryRef SourceFile)
Specify that a file is transient.
bool isFileOverridden(const FileEntry *File) const
Returns true if the file contents have been overridden.
OptionalFileEntryRef getFileEntryRefForID(FileID FID) const
Returns the FileEntryRef for the provided FileID.
SourceLocation translateLineCol(FileID FID, unsigned Line, unsigned Col) const
Get the source location in FID for the given line:col.
StringRef getBufferName(SourceLocation Loc, bool *Invalid=nullptr) const
Return the filename or buffer identifier of the buffer the location is in.
SourceLocation getTopMacroCallerLoc(SourceLocation Loc) const
std::optional< StringRef > getBufferDataOrNone(FileID FID) const
Return a StringRef to the source buffer data for the specified FileID, returning std::nullopt if inva...
unsigned getExpansionColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
FileID translateFile(const FileEntry *SourceFile) const
Get the FileID for the given file.
StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
FileID createFileID(FileEntryRef SourceFile, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, int LoadedID=0, SourceLocation::UIntTy LoadedOffset=0)
Create a new FileID that represents the specified file being #included from the specified IncludePosi...
void PrintStats() const
Print statistics to stderr.
FileID getUniqueLoadedASTFileID(SourceLocation Loc) const
bool isMainFile(const FileEntry &SourceFile)
Returns true when the given FileEntry corresponds to the main file.
size_t getDataStructureSizes() const
Return the amount of memory used for various side tables and data structures in the SourceManager.
bool isMacroArgExpansion(SourceLocation Loc, SourceLocation *StartLoc=nullptr) const
Tests whether the given source location represents a macro argument's expansion into the function-lik...
bool isInTheSameTranslationUnitImpl(const std::pair< FileID, unsigned > &LOffs, const std::pair< FileID, unsigned > &ROffs) const
Determines whether the two decomposed source location is in the same TU.
const SrcMgr::SLocEntry & getLocalSLocEntry(unsigned Index) const
Get a local SLocEntry. This is exposed for indexing.
OptionalFileEntryRef bypassFileContentsOverride(FileEntryRef File)
Bypass the overridden contents of a file.
FileManager & getFileManager() const
unsigned local_sloc_entry_size() const
Get the number of local SLocEntries we have.
std::optional< StringRef > getBufferDataIfLoaded(FileID FID) const
Return a StringRef to the source buffer data for the specified FileID, returning std::nullopt if it's...
const char * getCharacterData(SourceLocation SL, bool *Invalid=nullptr) const
Return a pointer to the start of the specified location in the appropriate spelling MemoryBuffer.
std::pair< int, SourceLocation::UIntTy > AllocateLoadedSLocEntries(unsigned NumSLocEntries, SourceLocation::UIntTy TotalSize)
Allocate a number of loaded SLocEntries, which will be actually loaded on demand from the external so...
void overrideFileContents(FileEntryRef SourceFile, const llvm::MemoryBufferRef &Buffer)
Override the contents of the given source file by providing an already-allocated buffer.
unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
unsigned getFileIDSize(FileID FID) const
The size of the SLocEntry that FID represents.
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Given a SourceLocation, return the spelling line number for the position indicated.
std::pair< bool, bool > isInTheSameTranslationUnit(std::pair< FileID, unsigned > &LOffs, std::pair< FileID, unsigned > &ROffs) const
Determines whether the two decomposed source location is in the same translation unit.
llvm::DenseMap< FileEntryRef, SrcMgr::ContentCache * >::const_iterator fileinfo_iterator
CharSourceRange getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
unsigned getSpellingColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
CharSourceRange getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
bool isInFileID(SourceLocation Loc, FileID FID, unsigned *RelativeOffset=nullptr) const
Given a specific FileID, returns true if Loc is inside that FileID chunk and sets relative offset (of...
unsigned getLineTableFilenameID(StringRef Str)
Return the uniqued ID for the specified filename.
std::pair< FileID, unsigned > getDecomposedExpansionLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
void initializeForReplay(const SourceManager &Old)
Initialize this source manager suitably to replay the compilation described by Old.
FileID getOrCreateFileID(FileEntryRef SourceFile, SrcMgr::CharacteristicKind FileCharacter)
Get the FileID for SourceFile if it exists.
SourceLocation translateFileLineCol(const FileEntry *SourceFile, unsigned Line, unsigned Col) const
Get the source location for the given file:line:col triplet.
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
std::pair< FileID, unsigned > getDecomposedSpellingLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
bool isAtStartOfImmediateMacroExpansion(SourceLocation Loc, SourceLocation *MacroBegin=nullptr) const
Returns true if the given MacroID location points at the beginning of the immediate macro expansion.
SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const
Return the file characteristic of the specified source location, indicating whether this is a normal ...
SourceLocation createExpansionLoc(SourceLocation SpellingLoc, SourceLocation ExpansionLocStart, SourceLocation ExpansionLocEnd, unsigned Length, bool ExpansionIsTokenRange=true, int LoadedID=0, SourceLocation::UIntTy LoadedOffset=0)
Creates an expansion SLocEntry for a macro use.
unsigned getPresumedColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
std::pair< FileID, unsigned > getDecomposedIncludedLoc(FileID FID) const
Returns the "included/expanded in" decomposed location of the given FileID.
StringRef getFilename(SourceLocation SpellingLoc) const
Return the filename of the file containing a SourceLocation.
SourceLocation getMacroArgExpandedLocation(SourceLocation Loc) const
If Loc points inside a function macro argument, the returned location will be the macro location in w...
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
std::optional< llvm::MemoryBufferRef > getBufferOrNone(FileID FID, SourceLocation Loc=SourceLocation()) const
Return the buffer for the specified FileID.
LineTableInfo & getLineTable()
Retrieve the stored line table.
SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID.
std::optional< llvm::MemoryBufferRef > getMemoryBufferForFileOrNone(FileEntryRef File)
Retrieve the memory buffer associated with the given file.
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
SourceLocation createMacroArgExpansionLoc(SourceLocation SpellingLoc, SourceLocation ExpansionLoc, unsigned Length)
Creates an expansion SLocEntry for the substitution of an argument into a function-like macro's body.
A trivial tuple used to represent a source range.
One instance of this struct is kept for every file loaded or used.
void setBuffer(std::unique_ptr< llvm::MemoryBuffer > B)
Set the buffer.
std::optional< StringRef > getBufferDataIfLoaded() const
Return a StringRef to the source buffer data, only if it has already been loaded.
OptionalFileEntryRef ContentsEntry
References the file which the contents were actually loaded from.
unsigned getSizeBytesMapped() const
Returns the number of bytes actually mapped for this ContentCache.
unsigned IsTransient
True if this file may be transient, that is, if it might not exist at some later point in time when t...
unsigned getSize() const
Returns the size of the content encapsulated by this ContentCache.
llvm::MemoryBuffer::BufferKind getMemoryBufferKind() const
Returns the kind of memory used to back the memory buffer for this content cache.
unsigned IsFileVolatile
True if this content cache was initially created for a source file considered to be volatile (likely ...
LineOffsetMapping SourceLineCache
A bump pointer allocated array of offsets for each source line.
std::optional< llvm::MemoryBufferRef > getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM, SourceLocation Loc=SourceLocation()) const
Returns the memory buffer for the associated content.
static const char * getInvalidBOM(StringRef BufStr)
unsigned BufferOverridden
Indicates whether the buffer itself was provided to override the actual file contents.
OptionalFileEntryRef OrigEntry
Reference to the file entry representing this ContentCache.
Each ExpansionInfo encodes the expansion location - where the token was ultimately expanded,...
SourceLocation getExpansionLocStart() const
static ExpansionInfo create(SourceLocation SpellingLoc, SourceLocation Start, SourceLocation End, bool ExpansionIsTokenRange=true)
Return a ExpansionInfo for an expansion.
bool isMacroBodyExpansion() const
SourceLocation getSpellingLoc() const
CharSourceRange getExpansionLocRange() const
bool isMacroArgExpansion() const
static ExpansionInfo createForMacroArg(SourceLocation SpellingLoc, SourceLocation ExpansionLoc)
Return a special ExpansionInfo for the expansion of a macro argument into a function-like macro's bod...
static ExpansionInfo createForTokenSplit(SourceLocation SpellingLoc, SourceLocation Start, SourceLocation End)
Return a special ExpansionInfo representing a token that ends prematurely.
SourceLocation getExpansionLocEnd() const
Information about a FileID, basically just the logical file that it represents and include stack info...
const ContentCache & getContentCache() const
CharacteristicKind getFileCharacteristic() const
Return whether this is a system header or not.
static FileInfo get(SourceLocation IL, ContentCache &Con, CharacteristicKind FileCharacter, StringRef Filename)
Return a FileInfo object.
bool hasLineDirectives() const
Return true if this FileID has #line directives in it.
void setHasLineDirectives()
Set the flag that indicates that this FileID has line table entries associated with it.
SourceLocation getIncludeLoc() const
StringRef getName() const
Returns the name of the file that was used when the file was loaded from the underlying file system.
Mapping of line offsets into a source file.
const unsigned * begin() const
LineOffsetMapping()=default
const unsigned * end() const
static LineOffsetMapping get(llvm::MemoryBufferRef Buffer, llvm::BumpPtrAllocator &Alloc)
This is a discriminated union of FileInfo and ExpansionInfo.
SourceLocation::UIntTy getOffset() const
static SLocEntry get(SourceLocation::UIntTy Offset, const FileInfo &FI)
const FileInfo & getFile() const
const ExpansionInfo & getExpansion() const
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
bool isSystem(CharacteristicKind CK)
Determine whether a file / directory characteristic is for system code.
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
SrcMgr::CharacteristicKind FileKind
Set the 0 if no flags, 1 if a system header,.
static LineEntry get(unsigned Offs, unsigned Line, int Filename, SrcMgr::CharacteristicKind FileKind, unsigned IncludeOffset)