1918e0ca7SEugene Zelenko //===- SourceManager.cpp - Track and cache source files -------------------===//
27a51313dSChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67a51313dSChris Lattner //
77a51313dSChris Lattner //===----------------------------------------------------------------------===//
87a51313dSChris Lattner //
97a51313dSChris Lattner // This file implements the SourceManager interface.
107a51313dSChris Lattner //
117a51313dSChris Lattner //===----------------------------------------------------------------------===//
127a51313dSChris Lattner
137a51313dSChris Lattner #include "clang/Basic/SourceManager.h"
14802b7760SDouglas Gregor #include "clang/Basic/Diagnostic.h"
157a51313dSChris Lattner #include "clang/Basic/FileManager.h"
16918e0ca7SEugene Zelenko #include "clang/Basic/LLVM.h"
17918e0ca7SEugene Zelenko #include "clang/Basic/SourceLocation.h"
183a02247dSChandler Carruth #include "clang/Basic/SourceManagerInternals.h"
19918e0ca7SEugene Zelenko #include "llvm/ADT/DenseMap.h"
20918e0ca7SEugene Zelenko #include "llvm/ADT/None.h"
21e08464fbSReid Kleckner #include "llvm/ADT/Optional.h"
2261ef3db2SArgyrios Kyrtzidis #include "llvm/ADT/STLExtras.h"
23918e0ca7SEugene Zelenko #include "llvm/ADT/SmallVector.h"
24918e0ca7SEugene Zelenko #include "llvm/ADT/StringRef.h"
25e08464fbSReid Kleckner #include "llvm/ADT/StringSwitch.h"
26918e0ca7SEugene Zelenko #include "llvm/Support/Allocator.h"
273a02247dSChandler Carruth #include "llvm/Support/Capacity.h"
287a51313dSChris Lattner #include "llvm/Support/Compiler.h"
2920105b6bSserge-sans-paille #include "llvm/Support/Endian.h"
30918e0ca7SEugene Zelenko #include "llvm/Support/ErrorHandling.h"
31918e0ca7SEugene Zelenko #include "llvm/Support/FileSystem.h"
32918e0ca7SEugene Zelenko #include "llvm/Support/MathExtras.h"
337a51313dSChris Lattner #include "llvm/Support/MemoryBuffer.h"
348aaf4995SMichael J. Spencer #include "llvm/Support/Path.h"
353a02247dSChandler Carruth #include "llvm/Support/raw_ostream.h"
367a51313dSChris Lattner #include <algorithm>
37918e0ca7SEugene Zelenko #include <cassert>
38918e0ca7SEugene Zelenko #include <cstddef>
39918e0ca7SEugene Zelenko #include <cstdint>
40918e0ca7SEugene Zelenko #include <memory>
41918e0ca7SEugene Zelenko #include <tuple>
42918e0ca7SEugene Zelenko #include <utility>
43918e0ca7SEugene Zelenko #include <vector>
44802b7760SDouglas Gregor
457a51313dSChris Lattner using namespace clang;
467a51313dSChris Lattner using namespace SrcMgr;
477a51313dSChris Lattner using llvm::MemoryBuffer;
487a51313dSChris Lattner
49153a0f1fSChris Lattner //===----------------------------------------------------------------------===//
504fa23625SChris Lattner // SourceManager Helper Classes
51153a0f1fSChris Lattner //===----------------------------------------------------------------------===//
524fa23625SChris Lattner
5364ee782eSChandler Carruth /// getSizeBytesMapped - Returns the number of bytes actually mapped for this
5464ee782eSChandler Carruth /// ContentCache. This can be 0 if the MemBuffer was not actually expanded.
getSizeBytesMapped() const5512c2af44STed Kremenek unsigned ContentCache::getSizeBytesMapped() const {
5629631451SDuncan P. N. Exon Smith return Buffer ? Buffer->getBufferSize() : 0;
5712c2af44STed Kremenek }
5812c2af44STed Kremenek
598d587900STed Kremenek /// Returns the kind of memory used to back the memory buffer for
608d587900STed Kremenek /// this content cache. This is used for performance analysis.
getMemoryBufferKind() const618d587900STed Kremenek llvm::MemoryBuffer::BufferKind ContentCache::getMemoryBufferKind() const {
62d8e5a0c4SZarko Todorovski if (Buffer == nullptr) {
63d8e5a0c4SZarko Todorovski assert(0 && "Buffer should never be null");
648d587900STed Kremenek return llvm::MemoryBuffer::MemoryBuffer_Malloc;
65d8e5a0c4SZarko Todorovski }
6629631451SDuncan P. N. Exon Smith return Buffer->getBufferKind();
678d587900STed Kremenek }
688d587900STed Kremenek
6912c2af44STed Kremenek /// getSize - Returns the size of the content encapsulated by this ContentCache.
7012c2af44STed Kremenek /// This can be the size of the source file or the size of an arbitrary
7112c2af44STed Kremenek /// scratch buffer. If the ContentCache encapsulates a source file, that
7253ad6b94SDouglas Gregor /// file is not lazily brought in from disk to satisfy this query.
getSize() const7312c2af44STed Kremenek unsigned ContentCache::getSize() const {
7429631451SDuncan P. N. Exon Smith return Buffer ? (unsigned)Buffer->getBufferSize()
7511e6f0a6SArgyrios Kyrtzidis : (unsigned)ContentsEntry->getSize();
7612c2af44STed Kremenek }
7712c2af44STed Kremenek
getInvalidBOM(StringRef BufStr)788fa5e98fSpaulhoad const char *ContentCache::getInvalidBOM(StringRef BufStr) {
798fa5e98fSpaulhoad // If the buffer is valid, check to see if it has a UTF Byte Order Mark
808fa5e98fSpaulhoad // (BOM). We only support UTF-8 with and without a BOM right now. See
818fa5e98fSpaulhoad // http://en.wikipedia.org/wiki/Byte_order_mark for more information.
828fa5e98fSpaulhoad const char *InvalidBOM =
838fa5e98fSpaulhoad llvm::StringSwitch<const char *>(BufStr)
848fa5e98fSpaulhoad .StartsWith(llvm::StringLiteral::withInnerNUL("\x00\x00\xFE\xFF"),
858fa5e98fSpaulhoad "UTF-32 (BE)")
868fa5e98fSpaulhoad .StartsWith(llvm::StringLiteral::withInnerNUL("\xFF\xFE\x00\x00"),
878fa5e98fSpaulhoad "UTF-32 (LE)")
888fa5e98fSpaulhoad .StartsWith("\xFE\xFF", "UTF-16 (BE)")
898fa5e98fSpaulhoad .StartsWith("\xFF\xFE", "UTF-16 (LE)")
908fa5e98fSpaulhoad .StartsWith("\x2B\x2F\x76", "UTF-7")
918fa5e98fSpaulhoad .StartsWith("\xF7\x64\x4C", "UTF-1")
928fa5e98fSpaulhoad .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC")
938fa5e98fSpaulhoad .StartsWith("\x0E\xFE\xFF", "SCSU")
948fa5e98fSpaulhoad .StartsWith("\xFB\xEE\x28", "BOCU-1")
958fa5e98fSpaulhoad .StartsWith("\x84\x31\x95\x33", "GB-18030")
968fa5e98fSpaulhoad .Default(nullptr);
978fa5e98fSpaulhoad
988fa5e98fSpaulhoad return InvalidBOM;
998fa5e98fSpaulhoad }
1008fa5e98fSpaulhoad
101d758f79eSDuncan P. N. Exon Smith llvm::Optional<llvm::MemoryBufferRef>
getBufferOrNone(DiagnosticsEngine & Diag,FileManager & FM,SourceLocation Loc) const102d758f79eSDuncan P. N. Exon Smith ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM,
103d758f79eSDuncan P. N. Exon Smith SourceLocation Loc) const {
1045631b052SChris Lattner // Lazily create the Buffer for ContentCaches that wrap files. If we already
10557540c5bSChris Lattner // computed it, just return what we have.
1061d78e210SDuncan P. N. Exon Smith if (IsBufferInvalid)
107747b134dSDuncan P. N. Exon Smith return None;
10829631451SDuncan P. N. Exon Smith if (Buffer)
10929631451SDuncan P. N. Exon Smith return Buffer->getMemBufferRef();
110d758f79eSDuncan P. N. Exon Smith if (!ContentsEntry)
111747b134dSDuncan P. N. Exon Smith return None;
1125631b052SChris Lattner
1134aa97e3dSDuncan P. N. Exon Smith // Start with the assumption that the buffer is invalid to simplify early
1144aa97e3dSDuncan P. N. Exon Smith // return paths.
1154aa97e3dSDuncan P. N. Exon Smith IsBufferInvalid = true;
1164aa97e3dSDuncan P. N. Exon Smith
117f5848190SDuncan P. N. Exon Smith auto BufferOrError = FM.getBufferForFile(ContentsEntry, IsFileVolatile);
1187cea5f17SDaniel Dunbar
1197cea5f17SDaniel Dunbar // If we were unable to open the file, then we are in an inconsistent
1207cea5f17SDaniel Dunbar // situation where the content cache referenced a file which no longer
1217cea5f17SDaniel Dunbar // exists. Most likely, we were using a stat cache with an invalid entry but
1227cea5f17SDaniel Dunbar // the file could also have been removed during processing. Since we can't
1237cea5f17SDaniel Dunbar // really deal with this situation, just create an empty buffer.
124a885796dSBenjamin Kramer if (!BufferOrError) {
12585795316SDouglas Gregor if (Diag.isDiagnosticInFlight())
12685795316SDouglas Gregor Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
127a885796dSBenjamin Kramer ContentsEntry->getName(),
128a885796dSBenjamin Kramer BufferOrError.getError().message());
12985795316SDouglas Gregor else
130d0040648SArgyrios Kyrtzidis Diag.Report(Loc, diag::err_cannot_open_file)
131a885796dSBenjamin Kramer << ContentsEntry->getName() << BufferOrError.getError().message();
13285795316SDouglas Gregor
133747b134dSDuncan P. N. Exon Smith return None;
1345631b052SChris Lattner }
1355631b052SChris Lattner
13629631451SDuncan P. N. Exon Smith Buffer = std::move(*BufferOrError);
137a885796dSBenjamin Kramer
138245218bbSDuncan P. N. Exon Smith // Check that the file's size fits in an 'unsigned' (with room for a
139245218bbSDuncan P. N. Exon Smith // past-the-end value). This is deeply regrettable, but various parts of
140245218bbSDuncan P. N. Exon Smith // Clang (including elsewhere in this file!) use 'unsigned' to represent file
141245218bbSDuncan P. N. Exon Smith // offsets, line numbers, string literal lengths, and so on, and fail
142245218bbSDuncan P. N. Exon Smith // miserably on large source files.
143245218bbSDuncan P. N. Exon Smith //
144245218bbSDuncan P. N. Exon Smith // Note: ContentsEntry could be a named pipe, in which case
145245218bbSDuncan P. N. Exon Smith // ContentsEntry::getSize() could have the wrong size. Use
146245218bbSDuncan P. N. Exon Smith // MemoryBuffer::getBufferSize() instead.
147245218bbSDuncan P. N. Exon Smith if (Buffer->getBufferSize() >= std::numeric_limits<unsigned>::max()) {
148245218bbSDuncan P. N. Exon Smith if (Diag.isDiagnosticInFlight())
149245218bbSDuncan P. N. Exon Smith Diag.SetDelayedDiagnostic(diag::err_file_too_large,
150245218bbSDuncan P. N. Exon Smith ContentsEntry->getName());
151245218bbSDuncan P. N. Exon Smith else
152245218bbSDuncan P. N. Exon Smith Diag.Report(Loc, diag::err_file_too_large)
153245218bbSDuncan P. N. Exon Smith << ContentsEntry->getName();
154245218bbSDuncan P. N. Exon Smith
155245218bbSDuncan P. N. Exon Smith return None;
156245218bbSDuncan P. N. Exon Smith }
157245218bbSDuncan P. N. Exon Smith
158245218bbSDuncan P. N. Exon Smith // Unless this is a named pipe (in which case we can handle a mismatch),
159245218bbSDuncan P. N. Exon Smith // check that the file's size is the same as in the file entry (which may
1604ac569b2SChris Lattner // have come from a stat cache).
161245218bbSDuncan P. N. Exon Smith if (!ContentsEntry->isNamedPipe() &&
162245218bbSDuncan P. N. Exon Smith Buffer->getBufferSize() != (size_t)ContentsEntry->getSize()) {
16385795316SDouglas Gregor if (Diag.isDiagnosticInFlight())
16485795316SDouglas Gregor Diag.SetDelayedDiagnostic(diag::err_file_modified,
16511e6f0a6SArgyrios Kyrtzidis ContentsEntry->getName());
16685795316SDouglas Gregor else
167d0040648SArgyrios Kyrtzidis Diag.Report(Loc, diag::err_file_modified)
16811e6f0a6SArgyrios Kyrtzidis << ContentsEntry->getName();
16985795316SDouglas Gregor
170747b134dSDuncan P. N. Exon Smith return None;
1717cea5f17SDaniel Dunbar }
1728fbe98b3SChris Lattner
1738fbe98b3SChris Lattner // If the buffer is valid, check to see if it has a UTF Byte Order Mark
1747f36a79eSEric Christopher // (BOM). We only support UTF-8 with and without a BOM right now. See
1758fbe98b3SChris Lattner // http://en.wikipedia.org/wiki/Byte_order_mark for more information.
17629631451SDuncan P. N. Exon Smith StringRef BufStr = Buffer->getBuffer();
1778fa5e98fSpaulhoad const char *InvalidBOM = getInvalidBOM(BufStr);
1788fbe98b3SChris Lattner
1797f36a79eSEric Christopher if (InvalidBOM) {
180d0040648SArgyrios Kyrtzidis Diag.Report(Loc, diag::err_unsupported_bom)
1817f36a79eSEric Christopher << InvalidBOM << ContentsEntry->getName();
182747b134dSDuncan P. N. Exon Smith return None;
183763ea559STed Kremenek }
184802b7760SDouglas Gregor
1854aa97e3dSDuncan P. N. Exon Smith // Buffer has been validated.
1864aa97e3dSDuncan P. N. Exon Smith IsBufferInvalid = false;
18729631451SDuncan P. N. Exon Smith return Buffer->getMemBufferRef();
18812c2af44STed Kremenek }
18912c2af44STed Kremenek
getLineTableFilenameID(StringRef Name)1900e62c1ccSChris Lattner unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) {
191eae2b49fSFangrui Song auto IterBool = FilenameIDs.try_emplace(Name, FilenamesByID.size());
19213156b68SDavid Blaikie if (IterBool.second)
19313156b68SDavid Blaikie FilenamesByID.push_back(&*IterBool.first);
19413156b68SDavid Blaikie return IterBool.first->second;
195b5fba6f8SChris Lattner }
196b5fba6f8SChris Lattner
197eb00ee07SReid Kleckner /// Add a line note to the line table that indicates that there is a \#line or
198eb00ee07SReid Kleckner /// GNU line marker at the specified FID/Offset location which changes the
199eb00ee07SReid Kleckner /// presumed location to LineNo/FilenameID. If EntryExit is 0, then this doesn't
200eb00ee07SReid Kleckner /// change the presumed \#include stack. If it is 1, this is a file entry, if
201eb00ee07SReid Kleckner /// it is 2 then this is a file exit. FileKind specifies whether this is a
202eb00ee07SReid Kleckner /// system header or extern C system header.
AddLineNote(FileID FID,unsigned Offset,unsigned LineNo,int FilenameID,unsigned EntryExit,SrcMgr::CharacteristicKind FileKind)203eb00ee07SReid Kleckner void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, unsigned LineNo,
204eb00ee07SReid Kleckner int FilenameID, unsigned EntryExit,
2050a1a8d85SChris Lattner SrcMgr::CharacteristicKind FileKind) {
2060a1a8d85SChris Lattner std::vector<LineEntry> &Entries = LineEntries[FID];
2070a1a8d85SChris Lattner
2080a1a8d85SChris Lattner assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
2090a1a8d85SChris Lattner "Adding line entries out of order!");
2100a1a8d85SChris Lattner
2111c967784SChris Lattner unsigned IncludeOffset = 0;
212bf6986d9SNathan Sidwell if (EntryExit == 1) {
213bf6986d9SNathan Sidwell // Push #include
2141c967784SChris Lattner IncludeOffset = Offset-1;
215bf6986d9SNathan Sidwell } else {
216bf6986d9SNathan Sidwell const auto *PrevEntry = Entries.empty() ? nullptr : &Entries.back();
217bf6986d9SNathan Sidwell if (EntryExit == 2) {
218bf6986d9SNathan Sidwell // Pop #include
219bf6986d9SNathan Sidwell assert(PrevEntry && PrevEntry->IncludeOffset &&
220bf6986d9SNathan Sidwell "PPDirectives should have caught case when popping empty include "
221bf6986d9SNathan Sidwell "stack");
222bf6986d9SNathan Sidwell PrevEntry = FindNearestLineEntry(FID, PrevEntry->IncludeOffset);
223bf6986d9SNathan Sidwell }
224bf6986d9SNathan Sidwell if (PrevEntry) {
2251c967784SChris Lattner IncludeOffset = PrevEntry->IncludeOffset;
226bf6986d9SNathan Sidwell if (FilenameID == -1) {
227bf6986d9SNathan Sidwell // An unspecified FilenameID means use the previous (or containing)
228bf6986d9SNathan Sidwell // filename if available, or the main source file otherwise.
229bf6986d9SNathan Sidwell FilenameID = PrevEntry->FilenameID;
230bf6986d9SNathan Sidwell }
231bf6986d9SNathan Sidwell }
2321c967784SChris Lattner }
2330a1a8d85SChris Lattner
2341c967784SChris Lattner Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, FileKind,
2351c967784SChris Lattner IncludeOffset));
2360a1a8d85SChris Lattner }
2370a1a8d85SChris Lattner
238d4293922SChris Lattner /// FindNearestLineEntry - Find the line entry nearest to FID that is before
239d4293922SChris Lattner /// it. If there is no line entry before Offset in FID, return null.
FindNearestLineEntry(FileID FID,unsigned Offset)24002c2dbf4SDouglas Gregor const LineEntry *LineTableInfo::FindNearestLineEntry(FileID FID,
241d4293922SChris Lattner unsigned Offset) {
242d4293922SChris Lattner const std::vector<LineEntry> &Entries = LineEntries[FID];
243d4293922SChris Lattner assert(!Entries.empty() && "No #line entries for this FID after all!");
244d4293922SChris Lattner
245334a2adaSChris Lattner // It is very common for the query to be after the last #line, check this
246334a2adaSChris Lattner // first.
247334a2adaSChris Lattner if (Entries.back().FileOffset <= Offset)
248334a2adaSChris Lattner return &Entries.back();
249d4293922SChris Lattner
250334a2adaSChris Lattner // Do a binary search to find the maximal element that is still before Offset.
2517264a474SFangrui Song std::vector<LineEntry>::const_iterator I = llvm::upper_bound(Entries, Offset);
2527264a474SFangrui Song if (I == Entries.begin())
2537264a474SFangrui Song return nullptr;
254334a2adaSChris Lattner return &*--I;
255d4293922SChris Lattner }
2566e0e1f49SChris Lattner
2579fc8faf9SAdrian Prantl /// Add a new line entry that has already been encoded into
2584c7626e7SDouglas Gregor /// the internal representation of the line table.
AddEntry(FileID FID,const std::vector<LineEntry> & Entries)25902c2dbf4SDouglas Gregor void LineTableInfo::AddEntry(FileID FID,
2604c7626e7SDouglas Gregor const std::vector<LineEntry> &Entries) {
2614c7626e7SDouglas Gregor LineEntries[FID] = Entries;
2624c7626e7SDouglas Gregor }
2636e0e1f49SChris Lattner
264b5fba6f8SChris Lattner /// getLineTableFilenameID - Return the uniqued ID for the specified filename.
getLineTableFilenameID(StringRef Name)2650e62c1ccSChris Lattner unsigned SourceManager::getLineTableFilenameID(StringRef Name) {
2665eeeab7dSVedant Kumar return getLineTable().getLineTableFilenameID(Name);
267b5fba6f8SChris Lattner }
268b5fba6f8SChris Lattner
2691eaa70a6SChris Lattner /// AddLineNote - Add a line note to the line table for the FileID and offset
2701eaa70a6SChris Lattner /// specified by Loc. If FilenameID is -1, it is considered to be
2711eaa70a6SChris Lattner /// unspecified.
AddLineNote(SourceLocation Loc,unsigned LineNo,int FilenameID,bool IsFileEntry,bool IsFileExit,SrcMgr::CharacteristicKind FileKind)2721eaa70a6SChris Lattner void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
2730a1a8d85SChris Lattner int FilenameID, bool IsFileEntry,
274eb00ee07SReid Kleckner bool IsFileExit,
275eb00ee07SReid Kleckner SrcMgr::CharacteristicKind FileKind) {
276c7ca5218SChandler Carruth std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
27749f754f4SDouglas Gregor
27849f754f4SDouglas Gregor bool Invalid = false;
27949f754f4SDouglas Gregor const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
28049f754f4SDouglas Gregor if (!Entry.isFile() || Invalid)
28149f754f4SDouglas Gregor return;
28249f754f4SDouglas Gregor
28349f754f4SDouglas Gregor const SrcMgr::FileInfo &FileInfo = Entry.getFile();
2840a1a8d85SChris Lattner
2850a1a8d85SChris Lattner // Remember that this file has #line directives now if it doesn't already.
2860a1a8d85SChris Lattner const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
2870a1a8d85SChris Lattner
2885eeeab7dSVedant Kumar (void) getLineTable();
2890a1a8d85SChris Lattner
2900a1a8d85SChris Lattner unsigned EntryExit = 0;
2910a1a8d85SChris Lattner if (IsFileEntry)
2920a1a8d85SChris Lattner EntryExit = 1;
2930a1a8d85SChris Lattner else if (IsFileExit)
2940a1a8d85SChris Lattner EntryExit = 2;
2950a1a8d85SChris Lattner
29602c2dbf4SDouglas Gregor LineTable->AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID,
2970a1a8d85SChris Lattner EntryExit, FileKind);
2980a1a8d85SChris Lattner }
2990a1a8d85SChris Lattner
getLineTable()3004c7626e7SDouglas Gregor LineTableInfo &SourceManager::getLineTable() {
301f1186c5aSCraig Topper if (!LineTable)
302a2dcbd36SNico Weber LineTable.reset(new LineTableInfo());
3034c7626e7SDouglas Gregor return *LineTable;
3044c7626e7SDouglas Gregor }
3051eaa70a6SChris Lattner
306153a0f1fSChris Lattner //===----------------------------------------------------------------------===//
3074fa23625SChris Lattner // Private 'Create' methods.
308153a0f1fSChris Lattner //===----------------------------------------------------------------------===//
30912c2af44STed Kremenek
SourceManager(DiagnosticsEngine & Diag,FileManager & FileMgr,bool UserFilesAreVolatile)3106d7833f1SArgyrios Kyrtzidis SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr,
3116d7833f1SArgyrios Kyrtzidis bool UserFilesAreVolatile)
312918e0ca7SEugene Zelenko : Diag(Diag), FileMgr(FileMgr), UserFilesAreVolatile(UserFilesAreVolatile) {
313d0040648SArgyrios Kyrtzidis clearIDTables();
314d0040648SArgyrios Kyrtzidis Diag.setSourceManager(this);
315d0040648SArgyrios Kyrtzidis }
316d0040648SArgyrios Kyrtzidis
~SourceManager()317b5fba6f8SChris Lattner SourceManager::~SourceManager() {
318c8233df6SChris Lattner // Delete FileEntry objects corresponding to content caches. Since the actual
319c8233df6SChris Lattner // content cache objects are bump pointer allocated, we just have to run the
320c8233df6SChris Lattner // dtors, but we call the deallocate method for completeness.
321c8233df6SChris Lattner for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i) {
322af41b3f0SArgyrios Kyrtzidis if (MemBufferInfos[i]) {
323c8233df6SChris Lattner MemBufferInfos[i]->~ContentCache();
324c8233df6SChris Lattner ContentCacheAlloc.Deallocate(MemBufferInfos[i]);
325c8233df6SChris Lattner }
326af41b3f0SArgyrios Kyrtzidis }
327c8233df6SChris Lattner for (llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::iterator
328c8233df6SChris Lattner I = FileInfos.begin(), E = FileInfos.end(); I != E; ++I) {
329af41b3f0SArgyrios Kyrtzidis if (I->second) {
330c8233df6SChris Lattner I->second->~ContentCache();
331c8233df6SChris Lattner ContentCacheAlloc.Deallocate(I->second);
332c8233df6SChris Lattner }
333af41b3f0SArgyrios Kyrtzidis }
334b5fba6f8SChris Lattner }
335b5fba6f8SChris Lattner
clearIDTables()336b5fba6f8SChris Lattner void SourceManager::clearIDTables() {
337b5fba6f8SChris Lattner MainFileID = FileID();
338925296b4SDouglas Gregor LocalSLocEntryTable.clear();
339925296b4SDouglas Gregor LoadedSLocEntryTable.clear();
340925296b4SDouglas Gregor SLocEntryLoaded.clear();
341b5fba6f8SChris Lattner LastLineNoFileIDQuery = FileID();
342f1186c5aSCraig Topper LastLineNoContentCache = nullptr;
343b5fba6f8SChris Lattner LastFileIDLookup = FileID();
344b5fba6f8SChris Lattner
345b5fba6f8SChris Lattner if (LineTable)
346b5fba6f8SChris Lattner LineTable->clear();
347b5fba6f8SChris Lattner
34864ee782eSChandler Carruth // Use up FileID #0 as an invalid expansion.
349925296b4SDouglas Gregor NextLocalOffset = 0;
35092a47bd9SArgyrios Kyrtzidis CurrentLoadedOffset = MaxLoadedOffset;
351115b077fSChandler Carruth createExpansionLoc(SourceLocation(), SourceLocation(), SourceLocation(), 1);
352b5fba6f8SChris Lattner }
353b5fba6f8SChris Lattner
isMainFile(const FileEntry & SourceFile)354168db924SDuncan P. N. Exon Smith bool SourceManager::isMainFile(const FileEntry &SourceFile) {
35511d612acSAlex Lorenz assert(MainFileID.isValid() && "expected initialized SourceManager");
356168db924SDuncan P. N. Exon Smith if (auto *FE = getFileEntryForID(MainFileID))
35711d612acSAlex Lorenz return FE->getUID() == SourceFile.getUID();
358168db924SDuncan P. N. Exon Smith return false;
35911d612acSAlex Lorenz }
36011d612acSAlex Lorenz
initializeForReplay(const SourceManager & Old)361ab75597dSRichard Smith void SourceManager::initializeForReplay(const SourceManager &Old) {
362ab75597dSRichard Smith assert(MainFileID.isInvalid() && "expected uninitialized SourceManager");
363ab75597dSRichard Smith
364ab75597dSRichard Smith auto CloneContentCache = [&](const ContentCache *Cache) -> ContentCache * {
365ab75597dSRichard Smith auto *Clone = new (ContentCacheAlloc.Allocate<ContentCache>()) ContentCache;
366ab75597dSRichard Smith Clone->OrigEntry = Cache->OrigEntry;
367ab75597dSRichard Smith Clone->ContentsEntry = Cache->ContentsEntry;
368ab75597dSRichard Smith Clone->BufferOverridden = Cache->BufferOverridden;
369f5848190SDuncan P. N. Exon Smith Clone->IsFileVolatile = Cache->IsFileVolatile;
370ab75597dSRichard Smith Clone->IsTransient = Cache->IsTransient;
371156e8b37SDuncan P. N. Exon Smith Clone->setUnownedBuffer(Cache->getBufferIfLoaded());
372ab75597dSRichard Smith return Clone;
373ab75597dSRichard Smith };
374ab75597dSRichard Smith
375ab75597dSRichard Smith // Ensure all SLocEntries are loaded from the external source.
376ab75597dSRichard Smith for (unsigned I = 0, N = Old.LoadedSLocEntryTable.size(); I != N; ++I)
377ab75597dSRichard Smith if (!Old.SLocEntryLoaded[I])
378ab75597dSRichard Smith Old.loadSLocEntry(I, nullptr);
379ab75597dSRichard Smith
380ab75597dSRichard Smith // Inherit any content cache data from the old source manager.
381ab75597dSRichard Smith for (auto &FileInfo : Old.FileInfos) {
382ab75597dSRichard Smith SrcMgr::ContentCache *&Slot = FileInfos[FileInfo.first];
383ab75597dSRichard Smith if (Slot)
384ab75597dSRichard Smith continue;
385ab75597dSRichard Smith Slot = CloneContentCache(FileInfo.second);
386ab75597dSRichard Smith }
387ab75597dSRichard Smith }
388ab75597dSRichard Smith
getOrCreateContentCache(FileEntryRef FileEnt,bool isSystemFile)3898d67b9e2SDuncan P. N. Exon Smith ContentCache &SourceManager::getOrCreateContentCache(FileEntryRef FileEnt,
3906d7833f1SArgyrios Kyrtzidis bool isSystemFile) {
3917a51313dSChris Lattner // Do we already have information about this file?
392c8233df6SChris Lattner ContentCache *&Entry = FileInfos[FileEnt];
3930387015dSDuncan P. N. Exon Smith if (Entry)
3940387015dSDuncan P. N. Exon Smith return *Entry;
3957a51313dSChris Lattner
39647c48087SChandler Carruth // Nope, create a new Cache entry.
39747c48087SChandler Carruth Entry = ContentCacheAlloc.Allocate<ContentCache>();
39811e6f0a6SArgyrios Kyrtzidis
3996eec06d0SArgyrios Kyrtzidis if (OverriddenFilesInfo) {
40011e6f0a6SArgyrios Kyrtzidis // If the file contents are overridden with contents from another file,
40111e6f0a6SArgyrios Kyrtzidis // pass that file to ContentCache.
40211e6f0a6SArgyrios Kyrtzidis llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator
4036eec06d0SArgyrios Kyrtzidis overI = OverriddenFilesInfo->OverriddenFiles.find(FileEnt);
4046eec06d0SArgyrios Kyrtzidis if (overI == OverriddenFilesInfo->OverriddenFiles.end())
405c8233df6SChris Lattner new (Entry) ContentCache(FileEnt);
40611e6f0a6SArgyrios Kyrtzidis else
40797d3a38cSArgyrios Kyrtzidis new (Entry) ContentCache(OverridenFilesKeepOriginalName ? FileEnt
40897d3a38cSArgyrios Kyrtzidis : overI->second,
40997d3a38cSArgyrios Kyrtzidis overI->second);
4106eec06d0SArgyrios Kyrtzidis } else {
4116eec06d0SArgyrios Kyrtzidis new (Entry) ContentCache(FileEnt);
4126eec06d0SArgyrios Kyrtzidis }
41311e6f0a6SArgyrios Kyrtzidis
414f5848190SDuncan P. N. Exon Smith Entry->IsFileVolatile = UserFilesAreVolatile && !isSystemFile;
415a8cfffa3SRichard Smith Entry->IsTransient = FilesAreTransient;
4168d67b9e2SDuncan P. N. Exon Smith Entry->BufferOverridden |= FileEnt.isNamedPipe();
4176d7833f1SArgyrios Kyrtzidis
4180387015dSDuncan P. N. Exon Smith return *Entry;
4197a51313dSChris Lattner }
4207a51313dSChris Lattner
4216d9bc278SRichard Smith /// Create a new ContentCache for the specified memory buffer.
4226d9bc278SRichard Smith /// This does no caching.
createMemBufferContentCache(std::unique_ptr<llvm::MemoryBuffer> Buffer)4230387015dSDuncan P. N. Exon Smith ContentCache &SourceManager::createMemBufferContentCache(
42451d1d585SDuncan P. N. Exon Smith std::unique_ptr<llvm::MemoryBuffer> Buffer) {
42547c48087SChandler Carruth // Add a new ContentCache to the MemBufferInfos list and return it.
42647c48087SChandler Carruth ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>();
427c8233df6SChris Lattner new (Entry) ContentCache();
428c8233df6SChris Lattner MemBufferInfos.push_back(Entry);
42929631451SDuncan P. N. Exon Smith Entry->setBuffer(std::move(Buffer));
4300387015dSDuncan P. N. Exon Smith return *Entry;
4317a51313dSChris Lattner }
4327a51313dSChris Lattner
loadSLocEntry(unsigned Index,bool * Invalid) const433969fdfddSArgyrios Kyrtzidis const SrcMgr::SLocEntry &SourceManager::loadSLocEntry(unsigned Index,
434969fdfddSArgyrios Kyrtzidis bool *Invalid) const {
435969fdfddSArgyrios Kyrtzidis assert(!SLocEntryLoaded[Index]);
436969fdfddSArgyrios Kyrtzidis if (ExternalSLocEntries->ReadSLocEntry(-(static_cast<int>(Index) + 2))) {
437969fdfddSArgyrios Kyrtzidis if (Invalid)
438969fdfddSArgyrios Kyrtzidis *Invalid = true;
439969fdfddSArgyrios Kyrtzidis // If the file of the SLocEntry changed we could still have loaded it.
440969fdfddSArgyrios Kyrtzidis if (!SLocEntryLoaded[Index]) {
441969fdfddSArgyrios Kyrtzidis // Try to recover; create a SLocEntry so the rest of clang can handle it.
442aab50af8SDuncan P. N. Exon Smith if (!FakeSLocEntryForRecovery)
443aab50af8SDuncan P. N. Exon Smith FakeSLocEntryForRecovery = std::make_unique<SLocEntry>(SLocEntry::get(
4440387015dSDuncan P. N. Exon Smith 0, FileInfo::get(SourceLocation(), getFakeContentCacheForRecovery(),
445aab50af8SDuncan P. N. Exon Smith SrcMgr::C_User, "")));
446aab50af8SDuncan P. N. Exon Smith return *FakeSLocEntryForRecovery;
447969fdfddSArgyrios Kyrtzidis }
448969fdfddSArgyrios Kyrtzidis }
449969fdfddSArgyrios Kyrtzidis
450969fdfddSArgyrios Kyrtzidis return LoadedSLocEntryTable[Index];
451969fdfddSArgyrios Kyrtzidis }
452969fdfddSArgyrios Kyrtzidis
45321401a72SSimon Tatham std::pair<int, SourceLocation::UIntTy>
AllocateLoadedSLocEntries(unsigned NumSLocEntries,SourceLocation::UIntTy TotalSize)454925296b4SDouglas Gregor SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries,
45521401a72SSimon Tatham SourceLocation::UIntTy TotalSize) {
456925296b4SDouglas Gregor assert(ExternalSLocEntries && "Don't have an external sloc source");
45778d81ecfSRichard Smith // Make sure we're not about to run out of source locations.
45878d81ecfSRichard Smith if (CurrentLoadedOffset - TotalSize < NextLocalOffset)
45978d81ecfSRichard Smith return std::make_pair(0, 0);
460925296b4SDouglas Gregor LoadedSLocEntryTable.resize(LoadedSLocEntryTable.size() + NumSLocEntries);
461925296b4SDouglas Gregor SLocEntryLoaded.resize(LoadedSLocEntryTable.size());
462925296b4SDouglas Gregor CurrentLoadedOffset -= TotalSize;
463925296b4SDouglas Gregor int ID = LoadedSLocEntryTable.size();
464925296b4SDouglas Gregor return std::make_pair(-ID - 1, CurrentLoadedOffset);
4650bc12935SDouglas Gregor }
4660bc12935SDouglas Gregor
4679fc8faf9SAdrian Prantl /// As part of recovering from missing or changed content, produce a
46849f754f4SDouglas Gregor /// fake, non-empty buffer.
getFakeBufferForRecovery() const4690387015dSDuncan P. N. Exon Smith llvm::MemoryBufferRef SourceManager::getFakeBufferForRecovery() const {
47049f754f4SDouglas Gregor if (!FakeBufferForRecovery)
471d87f8d76SRafael Espindola FakeBufferForRecovery =
472d87f8d76SRafael Espindola llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>");
47349f754f4SDouglas Gregor
4740387015dSDuncan P. N. Exon Smith return *FakeBufferForRecovery;
47549f754f4SDouglas Gregor }
476258ae54aSDouglas Gregor
4779fc8faf9SAdrian Prantl /// As part of recovering from missing or changed content, produce a
478969fdfddSArgyrios Kyrtzidis /// fake content cache.
getFakeContentCacheForRecovery() const4790387015dSDuncan P. N. Exon Smith SrcMgr::ContentCache &SourceManager::getFakeContentCacheForRecovery() const {
480969fdfddSArgyrios Kyrtzidis if (!FakeContentCacheForRecovery) {
4812b3d49b6SJonas Devlieghere FakeContentCacheForRecovery = std::make_unique<SrcMgr::ContentCache>();
4820387015dSDuncan P. N. Exon Smith FakeContentCacheForRecovery->setUnownedBuffer(getFakeBufferForRecovery());
483969fdfddSArgyrios Kyrtzidis }
4840387015dSDuncan P. N. Exon Smith return *FakeContentCacheForRecovery;
485969fdfddSArgyrios Kyrtzidis }
486969fdfddSArgyrios Kyrtzidis
4879fc8faf9SAdrian Prantl /// Returns the previous in-order FileID or an invalid FileID if there
488065d720cSArgyrios Kyrtzidis /// is no previous one.
getPreviousFileID(FileID FID) const489065d720cSArgyrios Kyrtzidis FileID SourceManager::getPreviousFileID(FileID FID) const {
490065d720cSArgyrios Kyrtzidis if (FID.isInvalid())
491065d720cSArgyrios Kyrtzidis return FileID();
492065d720cSArgyrios Kyrtzidis
493065d720cSArgyrios Kyrtzidis int ID = FID.ID;
494065d720cSArgyrios Kyrtzidis if (ID == -1)
495065d720cSArgyrios Kyrtzidis return FileID();
496065d720cSArgyrios Kyrtzidis
497065d720cSArgyrios Kyrtzidis if (ID > 0) {
498065d720cSArgyrios Kyrtzidis if (ID-1 == 0)
499065d720cSArgyrios Kyrtzidis return FileID();
500065d720cSArgyrios Kyrtzidis } else if (unsigned(-(ID-1) - 2) >= LoadedSLocEntryTable.size()) {
501065d720cSArgyrios Kyrtzidis return FileID();
502065d720cSArgyrios Kyrtzidis }
503065d720cSArgyrios Kyrtzidis
504065d720cSArgyrios Kyrtzidis return FileID::get(ID-1);
505065d720cSArgyrios Kyrtzidis }
506065d720cSArgyrios Kyrtzidis
5079fc8faf9SAdrian Prantl /// Returns the next in-order FileID or an invalid FileID if there is
508065d720cSArgyrios Kyrtzidis /// no next one.
getNextFileID(FileID FID) const509065d720cSArgyrios Kyrtzidis FileID SourceManager::getNextFileID(FileID FID) const {
510065d720cSArgyrios Kyrtzidis if (FID.isInvalid())
511065d720cSArgyrios Kyrtzidis return FileID();
512065d720cSArgyrios Kyrtzidis
513065d720cSArgyrios Kyrtzidis int ID = FID.ID;
514065d720cSArgyrios Kyrtzidis if (ID > 0) {
515065d720cSArgyrios Kyrtzidis if (unsigned(ID+1) >= local_sloc_entry_size())
516065d720cSArgyrios Kyrtzidis return FileID();
517065d720cSArgyrios Kyrtzidis } else if (ID+1 >= -1) {
518065d720cSArgyrios Kyrtzidis return FileID();
519065d720cSArgyrios Kyrtzidis }
520065d720cSArgyrios Kyrtzidis
521065d720cSArgyrios Kyrtzidis return FileID::get(ID+1);
522065d720cSArgyrios Kyrtzidis }
523065d720cSArgyrios Kyrtzidis
5244fa23625SChris Lattner //===----------------------------------------------------------------------===//
52564ee782eSChandler Carruth // Methods to create new FileID's and macro expansions.
5264fa23625SChris Lattner //===----------------------------------------------------------------------===//
5277a51313dSChris Lattner
528e08464fbSReid Kleckner /// Create a new FileID that represents the specified file
529e08464fbSReid Kleckner /// being \#included from the specified IncludePosition.
530e08464fbSReid Kleckner ///
531e08464fbSReid Kleckner /// This translates NULL into standard input.
createFileID(const FileEntry * SourceFile,SourceLocation IncludePos,SrcMgr::CharacteristicKind FileCharacter,int LoadedID,SourceLocation::UIntTy LoadedOffset)532e08464fbSReid Kleckner FileID SourceManager::createFileID(const FileEntry *SourceFile,
533e08464fbSReid Kleckner SourceLocation IncludePos,
534e08464fbSReid Kleckner SrcMgr::CharacteristicKind FileCharacter,
53521401a72SSimon Tatham int LoadedID,
53621401a72SSimon Tatham SourceLocation::UIntTy LoadedOffset) {
53746b1645eSDuncan P. N. Exon Smith return createFileID(SourceFile->getLastRef(), IncludePos, FileCharacter,
538e08464fbSReid Kleckner LoadedID, LoadedOffset);
539e08464fbSReid Kleckner }
540e08464fbSReid Kleckner
createFileID(FileEntryRef SourceFile,SourceLocation IncludePos,SrcMgr::CharacteristicKind FileCharacter,int LoadedID,SourceLocation::UIntTy LoadedOffset)541e08464fbSReid Kleckner FileID SourceManager::createFileID(FileEntryRef SourceFile,
542e08464fbSReid Kleckner SourceLocation IncludePos,
543e08464fbSReid Kleckner SrcMgr::CharacteristicKind FileCharacter,
54421401a72SSimon Tatham int LoadedID,
54521401a72SSimon Tatham SourceLocation::UIntTy LoadedOffset) {
5468d67b9e2SDuncan P. N. Exon Smith SrcMgr::ContentCache &IR = getOrCreateContentCache(SourceFile,
5470387015dSDuncan P. N. Exon Smith isSystem(FileCharacter));
548245218bbSDuncan P. N. Exon Smith
549245218bbSDuncan P. N. Exon Smith // If this is a named pipe, immediately load the buffer to ensure subsequent
550245218bbSDuncan P. N. Exon Smith // calls to ContentCache::getSize() are accurate.
551245218bbSDuncan P. N. Exon Smith if (IR.ContentsEntry->isNamedPipe())
552245218bbSDuncan P. N. Exon Smith (void)IR.getBufferOrNone(Diag, getFileManager(), SourceLocation());
553245218bbSDuncan P. N. Exon Smith
5540387015dSDuncan P. N. Exon Smith return createFileIDImpl(IR, SourceFile.getName(), IncludePos, FileCharacter,
555e08464fbSReid Kleckner LoadedID, LoadedOffset);
556e08464fbSReid Kleckner }
557e08464fbSReid Kleckner
558e08464fbSReid Kleckner /// Create a new FileID that represents the specified memory buffer.
559e08464fbSReid Kleckner ///
560e08464fbSReid Kleckner /// This does no caching of the buffer and takes ownership of the
561e08464fbSReid Kleckner /// MemoryBuffer, so only pass a MemoryBuffer to this once.
createFileID(std::unique_ptr<llvm::MemoryBuffer> Buffer,SrcMgr::CharacteristicKind FileCharacter,int LoadedID,SourceLocation::UIntTy LoadedOffset,SourceLocation IncludeLoc)562e08464fbSReid Kleckner FileID SourceManager::createFileID(std::unique_ptr<llvm::MemoryBuffer> Buffer,
563e08464fbSReid Kleckner SrcMgr::CharacteristicKind FileCharacter,
56421401a72SSimon Tatham int LoadedID,
56521401a72SSimon Tatham SourceLocation::UIntTy LoadedOffset,
566e08464fbSReid Kleckner SourceLocation IncludeLoc) {
567e08464fbSReid Kleckner StringRef Name = Buffer->getBufferIdentifier();
5680387015dSDuncan P. N. Exon Smith return createFileIDImpl(createMemBufferContentCache(std::move(Buffer)), Name,
56951d1d585SDuncan P. N. Exon Smith IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
570e08464fbSReid Kleckner }
571e08464fbSReid Kleckner
572e08464fbSReid Kleckner /// Create a new FileID that represents the specified memory buffer.
573e08464fbSReid Kleckner ///
574e08464fbSReid Kleckner /// This does not take ownership of the MemoryBuffer. The memory buffer must
575e08464fbSReid Kleckner /// outlive the SourceManager.
createFileID(const llvm::MemoryBufferRef & Buffer,SrcMgr::CharacteristicKind FileCharacter,int LoadedID,SourceLocation::UIntTy LoadedOffset,SourceLocation IncludeLoc)57651d1d585SDuncan P. N. Exon Smith FileID SourceManager::createFileID(const llvm::MemoryBufferRef &Buffer,
577e08464fbSReid Kleckner SrcMgr::CharacteristicKind FileCharacter,
57821401a72SSimon Tatham int LoadedID,
57921401a72SSimon Tatham SourceLocation::UIntTy LoadedOffset,
580e08464fbSReid Kleckner SourceLocation IncludeLoc) {
58151d1d585SDuncan P. N. Exon Smith return createFileID(llvm::MemoryBuffer::getMemBuffer(Buffer), FileCharacter,
58251d1d585SDuncan P. N. Exon Smith LoadedID, LoadedOffset, IncludeLoc);
583e08464fbSReid Kleckner }
584e08464fbSReid Kleckner
585e08464fbSReid Kleckner /// Get the FileID for \p SourceFile if it exists. Otherwise, create a
586e08464fbSReid Kleckner /// new FileID for the \p SourceFile.
587e08464fbSReid Kleckner FileID
getOrCreateFileID(const FileEntry * SourceFile,SrcMgr::CharacteristicKind FileCharacter)588e08464fbSReid Kleckner SourceManager::getOrCreateFileID(const FileEntry *SourceFile,
589e08464fbSReid Kleckner SrcMgr::CharacteristicKind FileCharacter) {
590e08464fbSReid Kleckner FileID ID = translateFile(SourceFile);
591e08464fbSReid Kleckner return ID.isValid() ? ID : createFileID(SourceFile, SourceLocation(),
592e08464fbSReid Kleckner FileCharacter);
593e08464fbSReid Kleckner }
594e08464fbSReid Kleckner
595ce46f02aSDan Gohman /// createFileID - Create a new FileID for the specified ContentCache and
5967a51313dSChris Lattner /// include position. This works regardless of whether the ContentCache
5977a51313dSChris Lattner /// corresponds to a file or some other input source.
createFileIDImpl(ContentCache & File,StringRef Filename,SourceLocation IncludePos,SrcMgr::CharacteristicKind FileCharacter,int LoadedID,SourceLocation::UIntTy LoadedOffset)5980387015dSDuncan P. N. Exon Smith FileID SourceManager::createFileIDImpl(ContentCache &File, StringRef Filename,
5994c311643SNico Weber SourceLocation IncludePos,
600258ae54aSDouglas Gregor SrcMgr::CharacteristicKind FileCharacter,
60121401a72SSimon Tatham int LoadedID,
60221401a72SSimon Tatham SourceLocation::UIntTy LoadedOffset) {
603925296b4SDouglas Gregor if (LoadedID < 0) {
604925296b4SDouglas Gregor assert(LoadedID != -1 && "Loading sentinel FileID");
605925296b4SDouglas Gregor unsigned Index = unsigned(-LoadedID) - 2;
606925296b4SDouglas Gregor assert(Index < LoadedSLocEntryTable.size() && "FileID out of range");
607925296b4SDouglas Gregor assert(!SLocEntryLoaded[Index] && "FileID already loaded");
6084dc5573aSAlex Lorenz LoadedSLocEntryTable[Index] = SLocEntry::get(
6094dc5573aSAlex Lorenz LoadedOffset, FileInfo::get(IncludePos, File, FileCharacter, Filename));
610925296b4SDouglas Gregor SLocEntryLoaded[Index] = true;
611925296b4SDouglas Gregor return FileID::get(LoadedID);
612258ae54aSDouglas Gregor }
61374a87834SDuncan P. N. Exon Smith unsigned FileSize = File.getSize();
614bce360b7SDiogo Sampaio if (!(NextLocalOffset + FileSize + 1 > NextLocalOffset &&
615bce360b7SDiogo Sampaio NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset)) {
616bce360b7SDiogo Sampaio Diag.Report(IncludePos, diag::err_include_too_large);
617bce360b7SDiogo Sampaio return FileID();
618bce360b7SDiogo Sampaio }
6194dc5573aSAlex Lorenz LocalSLocEntryTable.push_back(
6204dc5573aSAlex Lorenz SLocEntry::get(NextLocalOffset,
6214dc5573aSAlex Lorenz FileInfo::get(IncludePos, File, FileCharacter, Filename)));
622925296b4SDouglas Gregor // We do a +1 here because we want a SourceLocation that means "the end of the
623925296b4SDouglas Gregor // file", e.g. for the "no newline at the end of the file" diagnostic.
624925296b4SDouglas Gregor NextLocalOffset += FileSize + 1;
6254fa23625SChris Lattner
6264fa23625SChris Lattner // Set LastFileIDLookup to the newly created file. The next getFileID call is
6274fa23625SChris Lattner // almost guaranteed to be from that file.
628925296b4SDouglas Gregor FileID FID = FileID::get(LocalSLocEntryTable.size()-1);
6290152c6cbSArgyrios Kyrtzidis return LastFileIDLookup = FID;
6307a51313dSChris Lattner }
6317a51313dSChris Lattner
createMacroArgExpansionLoc(SourceLocation SpellingLoc,SourceLocation ExpansionLoc,unsigned Length)632*ef7439bdSSam McCall SourceLocation SourceManager::createMacroArgExpansionLoc(
633*ef7439bdSSam McCall SourceLocation SpellingLoc, SourceLocation ExpansionLoc, unsigned Length) {
63473ee5d7fSChandler Carruth ExpansionInfo Info = ExpansionInfo::createForMacroArg(SpellingLoc,
63573ee5d7fSChandler Carruth ExpansionLoc);
636*ef7439bdSSam McCall return createExpansionLocImpl(Info, Length);
637402bb388SChandler Carruth }
638402bb388SChandler Carruth
createExpansionLoc(SourceLocation SpellingLoc,SourceLocation ExpansionLocStart,SourceLocation ExpansionLocEnd,unsigned Length,bool ExpansionIsTokenRange,int LoadedID,SourceLocation::UIntTy LoadedOffset)63921401a72SSimon Tatham SourceLocation SourceManager::createExpansionLoc(
64021401a72SSimon Tatham SourceLocation SpellingLoc, SourceLocation ExpansionLocStart,
641*ef7439bdSSam McCall SourceLocation ExpansionLocEnd, unsigned Length,
64221401a72SSimon Tatham bool ExpansionIsTokenRange, int LoadedID,
64321401a72SSimon Tatham SourceLocation::UIntTy LoadedOffset) {
644b5f8171aSRichard Smith ExpansionInfo Info = ExpansionInfo::create(
645b5f8171aSRichard Smith SpellingLoc, ExpansionLocStart, ExpansionLocEnd, ExpansionIsTokenRange);
646*ef7439bdSSam McCall return createExpansionLocImpl(Info, Length, LoadedID, LoadedOffset);
647402bb388SChandler Carruth }
648402bb388SChandler Carruth
createTokenSplitLoc(SourceLocation Spelling,SourceLocation TokenStart,SourceLocation TokenEnd)649b5f8171aSRichard Smith SourceLocation SourceManager::createTokenSplitLoc(SourceLocation Spelling,
650b5f8171aSRichard Smith SourceLocation TokenStart,
651b5f8171aSRichard Smith SourceLocation TokenEnd) {
652b5f8171aSRichard Smith assert(getFileID(TokenStart) == getFileID(TokenEnd) &&
653b5f8171aSRichard Smith "token spans multiple files");
654b5f8171aSRichard Smith return createExpansionLocImpl(
655b5f8171aSRichard Smith ExpansionInfo::createForTokenSplit(Spelling, TokenStart, TokenEnd),
656b5f8171aSRichard Smith TokenEnd.getOffset() - TokenStart.getOffset());
657b5f8171aSRichard Smith }
658b5f8171aSRichard Smith
659402bb388SChandler Carruth SourceLocation
createExpansionLocImpl(const ExpansionInfo & Info,unsigned Length,int LoadedID,SourceLocation::UIntTy LoadedOffset)66073ee5d7fSChandler Carruth SourceManager::createExpansionLocImpl(const ExpansionInfo &Info,
661*ef7439bdSSam McCall unsigned Length, int LoadedID,
66221401a72SSimon Tatham SourceLocation::UIntTy LoadedOffset) {
663925296b4SDouglas Gregor if (LoadedID < 0) {
664925296b4SDouglas Gregor assert(LoadedID != -1 && "Loading sentinel FileID");
665925296b4SDouglas Gregor unsigned Index = unsigned(-LoadedID) - 2;
666925296b4SDouglas Gregor assert(Index < LoadedSLocEntryTable.size() && "FileID out of range");
667925296b4SDouglas Gregor assert(!SLocEntryLoaded[Index] && "FileID already loaded");
66873ee5d7fSChandler Carruth LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset, Info);
669925296b4SDouglas Gregor SLocEntryLoaded[Index] = true;
670925296b4SDouglas Gregor return SourceLocation::getMacroLoc(LoadedOffset);
671258ae54aSDouglas Gregor }
67273ee5d7fSChandler Carruth LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, Info));
673*ef7439bdSSam McCall assert(NextLocalOffset + Length + 1 > NextLocalOffset &&
674*ef7439bdSSam McCall NextLocalOffset + Length + 1 <= CurrentLoadedOffset &&
675925296b4SDouglas Gregor "Ran out of source locations!");
676925296b4SDouglas Gregor // See createFileID for that +1.
677*ef7439bdSSam McCall NextLocalOffset += Length + 1;
678*ef7439bdSSam McCall return SourceLocation::getMacroLoc(NextLocalOffset - (Length + 1));
6797a51313dSChris Lattner }
6807a51313dSChris Lattner
6812dc7e0c6SDuncan P. N. Exon Smith llvm::Optional<llvm::MemoryBufferRef>
getMemoryBufferForFileOrNone(const FileEntry * File)6822dc7e0c6SDuncan P. N. Exon Smith SourceManager::getMemoryBufferForFileOrNone(const FileEntry *File) {
6838d67b9e2SDuncan P. N. Exon Smith SrcMgr::ContentCache &IR = getOrCreateContentCache(File->getLastRef());
6840387015dSDuncan P. N. Exon Smith return IR.getBufferOrNone(Diag, getFileManager(), SourceLocation());
68553ad6b94SDouglas Gregor }
68653ad6b94SDouglas Gregor
overrideFileContents(const FileEntry * SourceFile,std::unique_ptr<llvm::MemoryBuffer> Buffer)68729631451SDuncan P. N. Exon Smith void SourceManager::overrideFileContents(
68829631451SDuncan P. N. Exon Smith const FileEntry *SourceFile, std::unique_ptr<llvm::MemoryBuffer> Buffer) {
6898d67b9e2SDuncan P. N. Exon Smith SrcMgr::ContentCache &IR = getOrCreateContentCache(SourceFile->getLastRef());
69053ad6b94SDouglas Gregor
6910387015dSDuncan P. N. Exon Smith IR.setBuffer(std::move(Buffer));
6920387015dSDuncan P. N. Exon Smith IR.BufferOverridden = true;
6936eec06d0SArgyrios Kyrtzidis
6946eec06d0SArgyrios Kyrtzidis getOverriddenFilesInfo().OverriddenFilesWithBuffer.insert(SourceFile);
69553ad6b94SDouglas Gregor }
69653ad6b94SDouglas Gregor
overrideFileContents(const FileEntry * SourceFile,const FileEntry * NewFile)69711e6f0a6SArgyrios Kyrtzidis void SourceManager::overrideFileContents(const FileEntry *SourceFile,
69811e6f0a6SArgyrios Kyrtzidis const FileEntry *NewFile) {
69911e6f0a6SArgyrios Kyrtzidis assert(SourceFile->getSize() == NewFile->getSize() &&
70011e6f0a6SArgyrios Kyrtzidis "Different sizes, use the FileManager to create a virtual file with "
70111e6f0a6SArgyrios Kyrtzidis "the correct size");
70211e6f0a6SArgyrios Kyrtzidis assert(FileInfos.count(SourceFile) == 0 &&
70311e6f0a6SArgyrios Kyrtzidis "This function should be called at the initialization stage, before "
70411e6f0a6SArgyrios Kyrtzidis "any parsing occurs.");
7056eec06d0SArgyrios Kyrtzidis getOverriddenFilesInfo().OverriddenFiles[SourceFile] = NewFile;
7066eec06d0SArgyrios Kyrtzidis }
7076eec06d0SArgyrios Kyrtzidis
708ac40a2d8SDuncan P. N. Exon Smith Optional<FileEntryRef>
bypassFileContentsOverride(FileEntryRef File)709ac40a2d8SDuncan P. N. Exon Smith SourceManager::bypassFileContentsOverride(FileEntryRef File) {
710ac40a2d8SDuncan P. N. Exon Smith assert(isFileOverridden(&File.getFileEntry()));
711ac40a2d8SDuncan P. N. Exon Smith llvm::Optional<FileEntryRef> BypassFile = FileMgr.getBypassFile(File);
7126eec06d0SArgyrios Kyrtzidis
713e1b7f22bSDuncan P. N. Exon Smith // If the file can't be found in the FS, give up.
714e1b7f22bSDuncan P. N. Exon Smith if (!BypassFile)
715ac40a2d8SDuncan P. N. Exon Smith return None;
7166eec06d0SArgyrios Kyrtzidis
7178d67b9e2SDuncan P. N. Exon Smith (void)getOrCreateContentCache(*BypassFile);
718ac40a2d8SDuncan P. N. Exon Smith return BypassFile;
71911e6f0a6SArgyrios Kyrtzidis }
72011e6f0a6SArgyrios Kyrtzidis
setFileIsTransient(const FileEntry * File)721a8cfffa3SRichard Smith void SourceManager::setFileIsTransient(const FileEntry *File) {
7228d67b9e2SDuncan P. N. Exon Smith getOrCreateContentCache(File->getLastRef()).IsTransient = true;
723fb1e7f7dSRichard Smith }
724fb1e7f7dSRichard Smith
725cf593d22SDuncan P. N. Exon Smith Optional<StringRef>
getNonBuiltinFilenameForID(FileID FID) const726cf593d22SDuncan P. N. Exon Smith SourceManager::getNonBuiltinFilenameForID(FileID FID) const {
727b6c6daa9SDuncan P. N. Exon Smith if (const SrcMgr::SLocEntry *Entry = getSLocEntryForFile(FID))
72874a87834SDuncan P. N. Exon Smith if (Entry->getFile().getContentCache().OrigEntry)
729cf593d22SDuncan P. N. Exon Smith return Entry->getFile().getName();
730e08464fbSReid Kleckner return None;
731e08464fbSReid Kleckner }
732e08464fbSReid Kleckner
getBufferData(FileID FID,bool * Invalid) const7330e62c1ccSChris Lattner StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
734d758f79eSDuncan P. N. Exon Smith auto B = getBufferDataOrNone(FID);
73586af9844SDouglas Gregor if (Invalid)
736d758f79eSDuncan P. N. Exon Smith *Invalid = !B;
737d758f79eSDuncan P. N. Exon Smith return B ? *B : "<<<<<INVALID SOURCE LOCATION>>>>>";
73886af9844SDouglas Gregor }
73986af9844SDouglas Gregor
740d758f79eSDuncan P. N. Exon Smith llvm::Optional<StringRef>
getBufferDataIfLoaded(FileID FID) const741d758f79eSDuncan P. N. Exon Smith SourceManager::getBufferDataIfLoaded(FileID FID) const {
742b6c6daa9SDuncan P. N. Exon Smith if (const SrcMgr::SLocEntry *Entry = getSLocEntryForFile(FID))
74374a87834SDuncan P. N. Exon Smith return Entry->getFile().getContentCache().getBufferDataIfLoaded();
744d758f79eSDuncan P. N. Exon Smith return None;
745d758f79eSDuncan P. N. Exon Smith }
746d758f79eSDuncan P. N. Exon Smith
getBufferDataOrNone(FileID FID) const747d758f79eSDuncan P. N. Exon Smith llvm::Optional<StringRef> SourceManager::getBufferDataOrNone(FileID FID) const {
748b6c6daa9SDuncan P. N. Exon Smith if (const SrcMgr::SLocEntry *Entry = getSLocEntryForFile(FID))
74974a87834SDuncan P. N. Exon Smith if (auto B = Entry->getFile().getContentCache().getBufferOrNone(
750d758f79eSDuncan P. N. Exon Smith Diag, getFileManager(), SourceLocation()))
751d758f79eSDuncan P. N. Exon Smith return B->getBuffer();
752d758f79eSDuncan P. N. Exon Smith return None;
753802b7760SDouglas Gregor }
754d32480d3SChris Lattner
755153a0f1fSChris Lattner //===----------------------------------------------------------------------===//
7564fa23625SChris Lattner // SourceLocation manipulation methods.
757153a0f1fSChris Lattner //===----------------------------------------------------------------------===//
7584fa23625SChris Lattner
7599fc8faf9SAdrian Prantl /// Return the FileID for a SourceLocation.
7604fa23625SChris Lattner ///
761925296b4SDouglas Gregor /// This is the cache-miss path of getFileID. Not as hot as that function, but
762925296b4SDouglas Gregor /// still very important. It is responsible for finding the entry in the
763925296b4SDouglas Gregor /// SLocEntry tables that contains the specified location.
getFileIDSlow(SourceLocation::UIntTy SLocOffset) const76421401a72SSimon Tatham FileID SourceManager::getFileIDSlow(SourceLocation::UIntTy SLocOffset) const {
76549f754f4SDouglas Gregor if (!SLocOffset)
76649f754f4SDouglas Gregor return FileID::get(0);
7674fa23625SChris Lattner
768925296b4SDouglas Gregor // Now it is time to search for the correct file. See where the SLocOffset
769925296b4SDouglas Gregor // sits in the global view and consult local or loaded buffers for it.
770925296b4SDouglas Gregor if (SLocOffset < NextLocalOffset)
771925296b4SDouglas Gregor return getFileIDLocal(SLocOffset);
772925296b4SDouglas Gregor return getFileIDLoaded(SLocOffset);
773925296b4SDouglas Gregor }
774925296b4SDouglas Gregor
7759fc8faf9SAdrian Prantl /// Return the FileID for a SourceLocation with a low offset.
776925296b4SDouglas Gregor ///
777925296b4SDouglas Gregor /// This function knows that the SourceLocation is in a local buffer, not a
778925296b4SDouglas Gregor /// loaded one.
getFileIDLocal(SourceLocation::UIntTy SLocOffset) const77921401a72SSimon Tatham FileID SourceManager::getFileIDLocal(SourceLocation::UIntTy SLocOffset) const {
780925296b4SDouglas Gregor assert(SLocOffset < NextLocalOffset && "Bad function choice");
781925296b4SDouglas Gregor
7824fa23625SChris Lattner // After the first and second level caches, I see two common sorts of
78364ee782eSChandler Carruth // behavior: 1) a lot of searched FileID's are "near" the cached file
78464ee782eSChandler Carruth // location or are "near" the cached expansion location. 2) others are just
7854fa23625SChris Lattner // completely random and may be a very long way away.
7864fa23625SChris Lattner //
7874fa23625SChris Lattner // To handle this, we do a linear search for up to 8 steps to catch #1 quickly
7884fa23625SChris Lattner // then we fall back to a less cache efficient, but more scalable, binary
7894fa23625SChris Lattner // search to find the location.
7904fa23625SChris Lattner
7914fa23625SChris Lattner // See if this is near the file point - worst case we start scanning from the
7924fa23625SChris Lattner // most newly created FileID.
7932999b77fSBenjamin Kramer const SrcMgr::SLocEntry *I;
7944fa23625SChris Lattner
795925296b4SDouglas Gregor if (LastFileIDLookup.ID < 0 ||
796925296b4SDouglas Gregor LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) {
7974fa23625SChris Lattner // Neither loc prunes our search.
798925296b4SDouglas Gregor I = LocalSLocEntryTable.end();
7994fa23625SChris Lattner } else {
8004fa23625SChris Lattner // Perhaps it is near the file point.
801925296b4SDouglas Gregor I = LocalSLocEntryTable.begin()+LastFileIDLookup.ID;
8024fa23625SChris Lattner }
8034fa23625SChris Lattner
8044fa23625SChris Lattner // Find the FileID that contains this. "I" is an iterator that points to a
8054fa23625SChris Lattner // FileID whose offset is known to be larger than SLocOffset.
8064fa23625SChris Lattner unsigned NumProbes = 0;
807918e0ca7SEugene Zelenko while (true) {
8084fa23625SChris Lattner --I;
8094fa23625SChris Lattner if (I->getOffset() <= SLocOffset) {
810925296b4SDouglas Gregor FileID Res = FileID::get(int(I - LocalSLocEntryTable.begin()));
8117b8cf98bSNick Desaulniers // Remember it. We have good locality across FileID lookups.
8124fa23625SChris Lattner LastFileIDLookup = Res;
8134fa23625SChris Lattner NumLinearScans += NumProbes+1;
8144fa23625SChris Lattner return Res;
8154fa23625SChris Lattner }
8164fa23625SChris Lattner if (++NumProbes == 8)
8174fa23625SChris Lattner break;
8184fa23625SChris Lattner }
8194fa23625SChris Lattner
8204fa23625SChris Lattner // Convert "I" back into an index. We know that it is an entry whose index is
8214fa23625SChris Lattner // larger than the offset we are looking for.
822925296b4SDouglas Gregor unsigned GreaterIndex = I - LocalSLocEntryTable.begin();
8234fa23625SChris Lattner // LessIndex - This is the lower bound of the range that we're searching.
8244fa23625SChris Lattner // We know that the offset corresponding to the FileID is is less than
8254fa23625SChris Lattner // SLocOffset.
8264fa23625SChris Lattner unsigned LessIndex = 0;
8274fa23625SChris Lattner NumProbes = 0;
828918e0ca7SEugene Zelenko while (true) {
8294fa23625SChris Lattner unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex;
83021401a72SSimon Tatham SourceLocation::UIntTy MidOffset =
83121401a72SSimon Tatham getLocalSLocEntry(MiddleIndex).getOffset();
8324fa23625SChris Lattner
8334fa23625SChris Lattner ++NumProbes;
8344fa23625SChris Lattner
8354fa23625SChris Lattner // If the offset of the midpoint is too large, chop the high side of the
8364fa23625SChris Lattner // range to the midpoint.
8374fa23625SChris Lattner if (MidOffset > SLocOffset) {
8384fa23625SChris Lattner GreaterIndex = MiddleIndex;
8394fa23625SChris Lattner continue;
8404fa23625SChris Lattner }
8414fa23625SChris Lattner
8424fa23625SChris Lattner // If the middle index contains the value, succeed and return.
843408efffbSNick Desaulniers if (MiddleIndex + 1 == LocalSLocEntryTable.size() ||
844408efffbSNick Desaulniers SLocOffset < getLocalSLocEntry(MiddleIndex + 1).getOffset()) {
8454fa23625SChris Lattner FileID Res = FileID::get(MiddleIndex);
8464fa23625SChris Lattner
8477b8cf98bSNick Desaulniers // Remember it. We have good locality across FileID lookups.
8484fa23625SChris Lattner LastFileIDLookup = Res;
8494fa23625SChris Lattner NumBinaryProbes += NumProbes;
8504fa23625SChris Lattner return Res;
8514fa23625SChris Lattner }
8524fa23625SChris Lattner
8534fa23625SChris Lattner // Otherwise, move the low-side up to the middle index.
8544fa23625SChris Lattner LessIndex = MiddleIndex;
8554fa23625SChris Lattner }
8564fa23625SChris Lattner }
8574fa23625SChris Lattner
8589fc8faf9SAdrian Prantl /// Return the FileID for a SourceLocation with a high offset.
859925296b4SDouglas Gregor ///
860925296b4SDouglas Gregor /// This function knows that the SourceLocation is in a loaded buffer, not a
861925296b4SDouglas Gregor /// local one.
getFileIDLoaded(SourceLocation::UIntTy SLocOffset) const86221401a72SSimon Tatham FileID SourceManager::getFileIDLoaded(SourceLocation::UIntTy SLocOffset) const {
8638edffaa6SArgyrios Kyrtzidis if (SLocOffset < CurrentLoadedOffset) {
8648edffaa6SArgyrios Kyrtzidis assert(0 && "Invalid SLocOffset or bad function choice");
86525029d49SArgyrios Kyrtzidis return FileID();
8668edffaa6SArgyrios Kyrtzidis }
86725029d49SArgyrios Kyrtzidis
868925296b4SDouglas Gregor // Essentially the same as the local case, but the loaded array is sorted
869925296b4SDouglas Gregor // in the other direction.
870925296b4SDouglas Gregor
871925296b4SDouglas Gregor // First do a linear scan from the last lookup position, if possible.
872925296b4SDouglas Gregor unsigned I;
873925296b4SDouglas Gregor int LastID = LastFileIDLookup.ID;
874925296b4SDouglas Gregor if (LastID >= 0 || getLoadedSLocEntryByID(LastID).getOffset() < SLocOffset)
875925296b4SDouglas Gregor I = 0;
876925296b4SDouglas Gregor else
877925296b4SDouglas Gregor I = (-LastID - 2) + 1;
878925296b4SDouglas Gregor
879925296b4SDouglas Gregor unsigned NumProbes;
880925296b4SDouglas Gregor for (NumProbes = 0; NumProbes < 8; ++NumProbes, ++I) {
881925296b4SDouglas Gregor // Make sure the entry is loaded!
882925296b4SDouglas Gregor const SrcMgr::SLocEntry &E = getLoadedSLocEntry(I);
883925296b4SDouglas Gregor if (E.getOffset() <= SLocOffset) {
884925296b4SDouglas Gregor FileID Res = FileID::get(-int(I) - 2);
885925296b4SDouglas Gregor LastFileIDLookup = Res;
886925296b4SDouglas Gregor NumLinearScans += NumProbes + 1;
887925296b4SDouglas Gregor return Res;
888925296b4SDouglas Gregor }
889925296b4SDouglas Gregor }
890925296b4SDouglas Gregor
891925296b4SDouglas Gregor // Linear scan failed. Do the binary search. Note the reverse sorting of the
892925296b4SDouglas Gregor // table: GreaterIndex is the one where the offset is greater, which is
893925296b4SDouglas Gregor // actually a lower index!
894925296b4SDouglas Gregor unsigned GreaterIndex = I;
895925296b4SDouglas Gregor unsigned LessIndex = LoadedSLocEntryTable.size();
896925296b4SDouglas Gregor NumProbes = 0;
897918e0ca7SEugene Zelenko while (true) {
898925296b4SDouglas Gregor ++NumProbes;
899925296b4SDouglas Gregor unsigned MiddleIndex = (LessIndex - GreaterIndex) / 2 + GreaterIndex;
900925296b4SDouglas Gregor const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex);
9017dc4f33cSArgyrios Kyrtzidis if (E.getOffset() == 0)
9027dc4f33cSArgyrios Kyrtzidis return FileID(); // invalid entry.
903925296b4SDouglas Gregor
904925296b4SDouglas Gregor ++NumProbes;
905925296b4SDouglas Gregor
906925296b4SDouglas Gregor if (E.getOffset() > SLocOffset) {
9077dc4f33cSArgyrios Kyrtzidis if (GreaterIndex == MiddleIndex) {
9087dc4f33cSArgyrios Kyrtzidis assert(0 && "binary search missed the entry");
9097dc4f33cSArgyrios Kyrtzidis return FileID();
9107dc4f33cSArgyrios Kyrtzidis }
911925296b4SDouglas Gregor GreaterIndex = MiddleIndex;
912925296b4SDouglas Gregor continue;
913925296b4SDouglas Gregor }
914925296b4SDouglas Gregor
915925296b4SDouglas Gregor if (isOffsetInFileID(FileID::get(-int(MiddleIndex) - 2), SLocOffset)) {
916925296b4SDouglas Gregor FileID Res = FileID::get(-int(MiddleIndex) - 2);
917925296b4SDouglas Gregor LastFileIDLookup = Res;
918925296b4SDouglas Gregor NumBinaryProbes += NumProbes;
919925296b4SDouglas Gregor return Res;
920925296b4SDouglas Gregor }
921925296b4SDouglas Gregor
9221ca73445SArgyrios Kyrtzidis if (LessIndex == MiddleIndex) {
9231ca73445SArgyrios Kyrtzidis assert(0 && "binary search missed the entry");
9241ca73445SArgyrios Kyrtzidis return FileID();
9251ca73445SArgyrios Kyrtzidis }
926925296b4SDouglas Gregor LessIndex = MiddleIndex;
927925296b4SDouglas Gregor }
928925296b4SDouglas Gregor }
929925296b4SDouglas Gregor
930659ac5f0SChris Lattner SourceLocation SourceManager::
getExpansionLocSlowCase(SourceLocation Loc) const931c84d769cSChandler Carruth getExpansionLocSlowCase(SourceLocation Loc) const {
932659ac5f0SChris Lattner do {
9335647d319SChris Lattner // Note: If Loc indicates an offset into a token that came from a macro
9345647d319SChris Lattner // expansion (e.g. the 5th character of the token) we do not want to add
935ee4c1d12SChandler Carruth // this offset when going to the expansion location. The expansion
9365647d319SChris Lattner // location is the macro invocation, which the offset has nothing to do
9375647d319SChris Lattner // with. This is unlike when we get the spelling loc, because the offset
9385647d319SChris Lattner // directly correspond to the token whose spelling we're inspecting.
939ee4c1d12SChandler Carruth Loc = getSLocEntry(getFileID(Loc)).getExpansion().getExpansionLocStart();
940659ac5f0SChris Lattner } while (!Loc.isFileID());
941659ac5f0SChris Lattner
942659ac5f0SChris Lattner return Loc;
943659ac5f0SChris Lattner }
944659ac5f0SChris Lattner
getSpellingLocSlowCase(SourceLocation Loc) const945659ac5f0SChris Lattner SourceLocation SourceManager::getSpellingLocSlowCase(SourceLocation Loc) const {
946659ac5f0SChris Lattner do {
947659ac5f0SChris Lattner std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc);
948ee4c1d12SChandler Carruth Loc = getSLocEntry(LocInfo.first).getExpansion().getSpellingLoc();
949e6e67deeSArgyrios Kyrtzidis Loc = Loc.getLocWithOffset(LocInfo.second);
950659ac5f0SChris Lattner } while (!Loc.isFileID());
951659ac5f0SChris Lattner return Loc;
952659ac5f0SChris Lattner }
953659ac5f0SChris Lattner
getFileLocSlowCase(SourceLocation Loc) const9547f6b029cSArgyrios Kyrtzidis SourceLocation SourceManager::getFileLocSlowCase(SourceLocation Loc) const {
9557f6b029cSArgyrios Kyrtzidis do {
9567f6b029cSArgyrios Kyrtzidis if (isMacroArgExpansion(Loc))
9577f6b029cSArgyrios Kyrtzidis Loc = getImmediateSpellingLoc(Loc);
9587f6b029cSArgyrios Kyrtzidis else
959b5f8171aSRichard Smith Loc = getImmediateExpansionRange(Loc).getBegin();
9607f6b029cSArgyrios Kyrtzidis } while (!Loc.isFileID());
9617f6b029cSArgyrios Kyrtzidis return Loc;
9627f6b029cSArgyrios Kyrtzidis }
9637f6b029cSArgyrios Kyrtzidis
964659ac5f0SChris Lattner
9654fa23625SChris Lattner std::pair<FileID, unsigned>
getDecomposedExpansionLocSlowCase(const SrcMgr::SLocEntry * E) const966c7ca5218SChandler Carruth SourceManager::getDecomposedExpansionLocSlowCase(
967c8f7e213SArgyrios Kyrtzidis const SrcMgr::SLocEntry *E) const {
96864ee782eSChandler Carruth // If this is an expansion record, walk through all the expansion points.
9694fa23625SChris Lattner FileID FID;
9704fa23625SChris Lattner SourceLocation Loc;
971c8f7e213SArgyrios Kyrtzidis unsigned Offset;
9724fa23625SChris Lattner do {
973ee4c1d12SChandler Carruth Loc = E->getExpansion().getExpansionLocStart();
9744fa23625SChris Lattner
9754fa23625SChris Lattner FID = getFileID(Loc);
9764fa23625SChris Lattner E = &getSLocEntry(FID);
977c8f7e213SArgyrios Kyrtzidis Offset = Loc.getOffset()-E->getOffset();
97831af4e08SChris Lattner } while (!Loc.isFileID());
9794fa23625SChris Lattner
9804fa23625SChris Lattner return std::make_pair(FID, Offset);
9814fa23625SChris Lattner }
9824fa23625SChris Lattner
9834fa23625SChris Lattner std::pair<FileID, unsigned>
getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry * E,unsigned Offset) const9844fa23625SChris Lattner SourceManager::getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
9854fa23625SChris Lattner unsigned Offset) const {
98664ee782eSChandler Carruth // If this is an expansion record, walk through all the expansion points.
98731af4e08SChris Lattner FileID FID;
98831af4e08SChris Lattner SourceLocation Loc;
98931af4e08SChris Lattner do {
990ee4c1d12SChandler Carruth Loc = E->getExpansion().getSpellingLoc();
991e6e67deeSArgyrios Kyrtzidis Loc = Loc.getLocWithOffset(Offset);
99231af4e08SChris Lattner
99331af4e08SChris Lattner FID = getFileID(Loc);
9944fa23625SChris Lattner E = &getSLocEntry(FID);
9952797df6aSArgyrios Kyrtzidis Offset = Loc.getOffset()-E->getOffset();
99631af4e08SChris Lattner } while (!Loc.isFileID());
99731af4e08SChris Lattner
9984fa23625SChris Lattner return std::make_pair(FID, Offset);
9994fa23625SChris Lattner }
10004fa23625SChris Lattner
10018ad52d50SChris Lattner /// getImmediateSpellingLoc - Given a SourceLocation object, return the
10028ad52d50SChris Lattner /// spelling location referenced by the ID. This is the first level down
10038ad52d50SChris Lattner /// towards the place where the characters that make up the lexed token can be
10048ad52d50SChris Lattner /// found. This should not generally be used by clients.
getImmediateSpellingLoc(SourceLocation Loc) const10058ad52d50SChris Lattner SourceLocation SourceManager::getImmediateSpellingLoc(SourceLocation Loc) const{
10068ad52d50SChris Lattner if (Loc.isFileID()) return Loc;
10078ad52d50SChris Lattner std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc);
1008ee4c1d12SChandler Carruth Loc = getSLocEntry(LocInfo.first).getExpansion().getSpellingLoc();
1009e6e67deeSArgyrios Kyrtzidis return Loc.getLocWithOffset(LocInfo.second);
10108ad52d50SChris Lattner }
10118ad52d50SChris Lattner
1012e08464fbSReid Kleckner /// Return the filename of the file containing a SourceLocation.
getFilename(SourceLocation SpellingLoc) const1013e08464fbSReid Kleckner StringRef SourceManager::getFilename(SourceLocation SpellingLoc) const {
1014e08464fbSReid Kleckner if (const FileEntry *F = getFileEntryForID(getFileID(SpellingLoc)))
1015e08464fbSReid Kleckner return F->getName();
1016e08464fbSReid Kleckner return StringRef();
1017e08464fbSReid Kleckner }
1018e08464fbSReid Kleckner
101964ee782eSChandler Carruth /// getImmediateExpansionRange - Loc is required to be an expansion location.
102064ee782eSChandler Carruth /// Return the start/end of the expansion information.
1021b5f8171aSRichard Smith CharSourceRange
getImmediateExpansionRange(SourceLocation Loc) const1022ca757587SChandler Carruth SourceManager::getImmediateExpansionRange(SourceLocation Loc) const {
102364ee782eSChandler Carruth assert(Loc.isMacroID() && "Not a macro expansion loc!");
1024ee4c1d12SChandler Carruth const ExpansionInfo &Expansion = getSLocEntry(getFileID(Loc)).getExpansion();
102573ee5d7fSChandler Carruth return Expansion.getExpansionLocRange();
10269dc9c206SChris Lattner }
10279dc9c206SChris Lattner
getTopMacroCallerLoc(SourceLocation Loc) const1028441e8fdfSGeorge Karpenkov SourceLocation SourceManager::getTopMacroCallerLoc(SourceLocation Loc) const {
1029441e8fdfSGeorge Karpenkov while (isMacroArgExpansion(Loc))
1030441e8fdfSGeorge Karpenkov Loc = getImmediateSpellingLoc(Loc);
1031441e8fdfSGeorge Karpenkov return Loc;
1032441e8fdfSGeorge Karpenkov }
1033441e8fdfSGeorge Karpenkov
10346d28d7f2SChandler Carruth /// getExpansionRange - Given a SourceLocation object, return the range of
10356d28d7f2SChandler Carruth /// tokens covered by the expansion in the ultimate file.
getExpansionRange(SourceLocation Loc) const1036b5f8171aSRichard Smith CharSourceRange SourceManager::getExpansionRange(SourceLocation Loc) const {
1037b5f8171aSRichard Smith if (Loc.isFileID())
1038b5f8171aSRichard Smith return CharSourceRange(SourceRange(Loc, Loc), true);
1039f52c0b26SChris Lattner
1040b5f8171aSRichard Smith CharSourceRange Res = getImmediateExpansionRange(Loc);
1041f52c0b26SChris Lattner
104264ee782eSChandler Carruth // Fully resolve the start and end locations to their ultimate expansion
1043f52c0b26SChris Lattner // points.
1044b5f8171aSRichard Smith while (!Res.getBegin().isFileID())
1045b5f8171aSRichard Smith Res.setBegin(getImmediateExpansionRange(Res.getBegin()).getBegin());
1046b5f8171aSRichard Smith while (!Res.getEnd().isFileID()) {
1047b5f8171aSRichard Smith CharSourceRange EndRange = getImmediateExpansionRange(Res.getEnd());
1048b5f8171aSRichard Smith Res.setEnd(EndRange.getEnd());
1049b5f8171aSRichard Smith Res.setTokenRange(EndRange.isTokenRange());
1050b5f8171aSRichard Smith }
1051f52c0b26SChris Lattner return Res;
1052f52c0b26SChris Lattner }
1053f52c0b26SChris Lattner
isMacroArgExpansion(SourceLocation Loc,SourceLocation * StartLoc) const1054c3096249SRichard Trieu bool SourceManager::isMacroArgExpansion(SourceLocation Loc,
1055c3096249SRichard Trieu SourceLocation *StartLoc) const {
1056402bb388SChandler Carruth if (!Loc.isMacroID()) return false;
1057402bb388SChandler Carruth
1058402bb388SChandler Carruth FileID FID = getFileID(Loc);
1059b1e71a7dSMatt Beaumont-Gay const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion();
1060c3096249SRichard Trieu if (!Expansion.isMacroArgExpansion()) return false;
1061c3096249SRichard Trieu
1062c3096249SRichard Trieu if (StartLoc)
1063c3096249SRichard Trieu *StartLoc = Expansion.getExpansionLocStart();
1064c3096249SRichard Trieu return true;
1065402bb388SChandler Carruth }
10669dc9c206SChris Lattner
isMacroBodyExpansion(SourceLocation Loc) const1067b1e71a7dSMatt Beaumont-Gay bool SourceManager::isMacroBodyExpansion(SourceLocation Loc) const {
1068b1e71a7dSMatt Beaumont-Gay if (!Loc.isMacroID()) return false;
1069b1e71a7dSMatt Beaumont-Gay
1070b1e71a7dSMatt Beaumont-Gay FileID FID = getFileID(Loc);
1071b1e71a7dSMatt Beaumont-Gay const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion();
1072b1e71a7dSMatt Beaumont-Gay return Expansion.isMacroBodyExpansion();
1073b1e71a7dSMatt Beaumont-Gay }
1074b1e71a7dSMatt Beaumont-Gay
isAtStartOfImmediateMacroExpansion(SourceLocation Loc,SourceLocation * MacroBegin) const1075065d720cSArgyrios Kyrtzidis bool SourceManager::isAtStartOfImmediateMacroExpansion(SourceLocation Loc,
1076065d720cSArgyrios Kyrtzidis SourceLocation *MacroBegin) const {
1077065d720cSArgyrios Kyrtzidis assert(Loc.isValid() && Loc.isMacroID() && "Expected a valid macro loc");
1078065d720cSArgyrios Kyrtzidis
1079065d720cSArgyrios Kyrtzidis std::pair<FileID, unsigned> DecompLoc = getDecomposedLoc(Loc);
1080065d720cSArgyrios Kyrtzidis if (DecompLoc.second > 0)
1081065d720cSArgyrios Kyrtzidis return false; // Does not point at the start of expansion range.
1082065d720cSArgyrios Kyrtzidis
1083065d720cSArgyrios Kyrtzidis bool Invalid = false;
1084065d720cSArgyrios Kyrtzidis const SrcMgr::ExpansionInfo &ExpInfo =
1085065d720cSArgyrios Kyrtzidis getSLocEntry(DecompLoc.first, &Invalid).getExpansion();
1086065d720cSArgyrios Kyrtzidis if (Invalid)
1087065d720cSArgyrios Kyrtzidis return false;
1088065d720cSArgyrios Kyrtzidis SourceLocation ExpLoc = ExpInfo.getExpansionLocStart();
1089065d720cSArgyrios Kyrtzidis
1090065d720cSArgyrios Kyrtzidis if (ExpInfo.isMacroArgExpansion()) {
1091065d720cSArgyrios Kyrtzidis // For macro argument expansions, check if the previous FileID is part of
1092065d720cSArgyrios Kyrtzidis // the same argument expansion, in which case this Loc is not at the
1093065d720cSArgyrios Kyrtzidis // beginning of the expansion.
1094065d720cSArgyrios Kyrtzidis FileID PrevFID = getPreviousFileID(DecompLoc.first);
1095065d720cSArgyrios Kyrtzidis if (!PrevFID.isInvalid()) {
1096065d720cSArgyrios Kyrtzidis const SrcMgr::SLocEntry &PrevEntry = getSLocEntry(PrevFID, &Invalid);
1097065d720cSArgyrios Kyrtzidis if (Invalid)
1098065d720cSArgyrios Kyrtzidis return false;
1099065d720cSArgyrios Kyrtzidis if (PrevEntry.isExpansion() &&
1100065d720cSArgyrios Kyrtzidis PrevEntry.getExpansion().getExpansionLocStart() == ExpLoc)
1101065d720cSArgyrios Kyrtzidis return false;
1102065d720cSArgyrios Kyrtzidis }
1103065d720cSArgyrios Kyrtzidis }
1104065d720cSArgyrios Kyrtzidis
1105065d720cSArgyrios Kyrtzidis if (MacroBegin)
1106065d720cSArgyrios Kyrtzidis *MacroBegin = ExpLoc;
1107065d720cSArgyrios Kyrtzidis return true;
1108065d720cSArgyrios Kyrtzidis }
1109065d720cSArgyrios Kyrtzidis
isAtEndOfImmediateMacroExpansion(SourceLocation Loc,SourceLocation * MacroEnd) const1110065d720cSArgyrios Kyrtzidis bool SourceManager::isAtEndOfImmediateMacroExpansion(SourceLocation Loc,
1111065d720cSArgyrios Kyrtzidis SourceLocation *MacroEnd) const {
1112065d720cSArgyrios Kyrtzidis assert(Loc.isValid() && Loc.isMacroID() && "Expected a valid macro loc");
1113065d720cSArgyrios Kyrtzidis
1114065d720cSArgyrios Kyrtzidis FileID FID = getFileID(Loc);
1115065d720cSArgyrios Kyrtzidis SourceLocation NextLoc = Loc.getLocWithOffset(1);
1116065d720cSArgyrios Kyrtzidis if (isInFileID(NextLoc, FID))
1117065d720cSArgyrios Kyrtzidis return false; // Does not point at the end of expansion range.
1118065d720cSArgyrios Kyrtzidis
1119065d720cSArgyrios Kyrtzidis bool Invalid = false;
1120065d720cSArgyrios Kyrtzidis const SrcMgr::ExpansionInfo &ExpInfo =
1121065d720cSArgyrios Kyrtzidis getSLocEntry(FID, &Invalid).getExpansion();
1122065d720cSArgyrios Kyrtzidis if (Invalid)
1123065d720cSArgyrios Kyrtzidis return false;
1124065d720cSArgyrios Kyrtzidis
1125065d720cSArgyrios Kyrtzidis if (ExpInfo.isMacroArgExpansion()) {
1126065d720cSArgyrios Kyrtzidis // For macro argument expansions, check if the next FileID is part of the
1127065d720cSArgyrios Kyrtzidis // same argument expansion, in which case this Loc is not at the end of the
1128065d720cSArgyrios Kyrtzidis // expansion.
1129065d720cSArgyrios Kyrtzidis FileID NextFID = getNextFileID(FID);
1130065d720cSArgyrios Kyrtzidis if (!NextFID.isInvalid()) {
1131065d720cSArgyrios Kyrtzidis const SrcMgr::SLocEntry &NextEntry = getSLocEntry(NextFID, &Invalid);
1132065d720cSArgyrios Kyrtzidis if (Invalid)
1133065d720cSArgyrios Kyrtzidis return false;
1134065d720cSArgyrios Kyrtzidis if (NextEntry.isExpansion() &&
1135065d720cSArgyrios Kyrtzidis NextEntry.getExpansion().getExpansionLocStart() ==
1136065d720cSArgyrios Kyrtzidis ExpInfo.getExpansionLocStart())
1137065d720cSArgyrios Kyrtzidis return false;
1138065d720cSArgyrios Kyrtzidis }
1139065d720cSArgyrios Kyrtzidis }
1140065d720cSArgyrios Kyrtzidis
1141065d720cSArgyrios Kyrtzidis if (MacroEnd)
1142065d720cSArgyrios Kyrtzidis *MacroEnd = ExpInfo.getExpansionLocEnd();
1143065d720cSArgyrios Kyrtzidis return true;
1144065d720cSArgyrios Kyrtzidis }
1145065d720cSArgyrios Kyrtzidis
11464fa23625SChris Lattner //===----------------------------------------------------------------------===//
11474fa23625SChris Lattner // Queries about the code at a SourceLocation.
11484fa23625SChris Lattner //===----------------------------------------------------------------------===//
11497a51313dSChris Lattner
11507a51313dSChris Lattner /// getCharacterData - Return a pointer to the start of the specified location
11517a51313dSChris Lattner /// in the appropriate MemoryBuffer.
getCharacterData(SourceLocation SL,bool * Invalid) const11527bda4b83SDouglas Gregor const char *SourceManager::getCharacterData(SourceLocation SL,
11537bda4b83SDouglas Gregor bool *Invalid) const {
11547a51313dSChris Lattner // Note that this is a hot function in the getSpelling() path, which is
11557a51313dSChris Lattner // heavily used by -E mode.
11564fa23625SChris Lattner std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(SL);
1157d32480d3SChris Lattner
115812c2af44STed Kremenek // Note that calling 'getBuffer()' may lazily page in a source file.
11597bda4b83SDouglas Gregor bool CharDataInvalid = false;
116049f754f4SDouglas Gregor const SLocEntry &Entry = getSLocEntry(LocInfo.first, &CharDataInvalid);
116149f754f4SDouglas Gregor if (CharDataInvalid || !Entry.isFile()) {
116249f754f4SDouglas Gregor if (Invalid)
116349f754f4SDouglas Gregor *Invalid = true;
116449f754f4SDouglas Gregor
116549f754f4SDouglas Gregor return "<<<<INVALID BUFFER>>>>";
116649f754f4SDouglas Gregor }
1167d758f79eSDuncan P. N. Exon Smith llvm::Optional<llvm::MemoryBufferRef> Buffer =
116874a87834SDuncan P. N. Exon Smith Entry.getFile().getContentCache().getBufferOrNone(Diag, getFileManager(),
1169d758f79eSDuncan P. N. Exon Smith SourceLocation());
11707bda4b83SDouglas Gregor if (Invalid)
1171d758f79eSDuncan P. N. Exon Smith *Invalid = !Buffer;
1172d758f79eSDuncan P. N. Exon Smith return Buffer ? Buffer->getBufferStart() + LocInfo.second
1173d758f79eSDuncan P. N. Exon Smith : "<<<<INVALID BUFFER>>>>";
11747a51313dSChris Lattner }
11757a51313dSChris Lattner
11767a51313dSChris Lattner /// getColumnNumber - Return the column # for the specified file position.
1177e4ad4176SChris Lattner /// this is significantly cheaper to compute than the line number.
getColumnNumber(FileID FID,unsigned FilePos,bool * Invalid) const11787bda4b83SDouglas Gregor unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
11797bda4b83SDouglas Gregor bool *Invalid) const {
118054c1bcabSDuncan P. N. Exon Smith llvm::Optional<llvm::MemoryBufferRef> MemBuf = getBufferOrNone(FID);
11817bda4b83SDouglas Gregor if (Invalid)
118254c1bcabSDuncan P. N. Exon Smith *Invalid = !MemBuf;
11837bda4b83SDouglas Gregor
118454c1bcabSDuncan P. N. Exon Smith if (!MemBuf)
11857bda4b83SDouglas Gregor return 1;
11867a51313dSChris Lattner
11878d63d5b8SJordan Rose // It is okay to request a position just past the end of the buffer.
11888d63d5b8SJordan Rose if (FilePos > MemBuf->getBufferSize()) {
11896c8d29f7SArgyrios Kyrtzidis if (Invalid)
11908d63d5b8SJordan Rose *Invalid = true;
11916c8d29f7SArgyrios Kyrtzidis return 1;
11926c8d29f7SArgyrios Kyrtzidis }
11936c8d29f7SArgyrios Kyrtzidis
1194a0b99e45SChih-Hung Hsieh const char *Buf = MemBuf->getBufferStart();
11955e79ee08SCraig Topper // See if we just calculated the line number for this FilePos and can use
11965e79ee08SCraig Topper // that to lookup the start of the line instead of searching for it.
1197dbbc4f4eSDuncan P. N. Exon Smith if (LastLineNoFileIDQuery == FID && LastLineNoContentCache->SourceLineCache &&
1198dbbc4f4eSDuncan P. N. Exon Smith LastLineNoResult < LastLineNoContentCache->SourceLineCache.size()) {
1199dbbc4f4eSDuncan P. N. Exon Smith const unsigned *SourceLineCache =
1200dbbc4f4eSDuncan P. N. Exon Smith LastLineNoContentCache->SourceLineCache.begin();
12015e79ee08SCraig Topper unsigned LineStart = SourceLineCache[LastLineNoResult - 1];
12025e79ee08SCraig Topper unsigned LineEnd = SourceLineCache[LastLineNoResult];
1203a0b99e45SChih-Hung Hsieh if (FilePos >= LineStart && FilePos < LineEnd) {
1204a0b99e45SChih-Hung Hsieh // LineEnd is the LineStart of the next line.
1205a0b99e45SChih-Hung Hsieh // A line ends with separator LF or CR+LF on Windows.
1206a0b99e45SChih-Hung Hsieh // FilePos might point to the last separator,
1207a0b99e45SChih-Hung Hsieh // but we need a column number at most 1 + the last column.
1208a0b99e45SChih-Hung Hsieh if (FilePos + 1 == LineEnd && FilePos > LineStart) {
1209a0b99e45SChih-Hung Hsieh if (Buf[FilePos - 1] == '\r' || Buf[FilePos - 1] == '\n')
1210a0b99e45SChih-Hung Hsieh --FilePos;
1211a0b99e45SChih-Hung Hsieh }
12125e79ee08SCraig Topper return FilePos - LineStart + 1;
12135e79ee08SCraig Topper }
1214a0b99e45SChih-Hung Hsieh }
12155e79ee08SCraig Topper
12167a51313dSChris Lattner unsigned LineStart = FilePos;
12177a51313dSChris Lattner while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
12187a51313dSChris Lattner --LineStart;
12197a51313dSChris Lattner return FilePos-LineStart+1;
12207a51313dSChris Lattner }
12217a51313dSChris Lattner
1222ea6d7f33SZhanyong Wan // isInvalid - Return the result of calling loc.isInvalid(), and
1223ea6d7f33SZhanyong Wan // if Invalid is not null, set its value to same.
122441e66291SRichard Smith template<typename LocType>
isInvalid(LocType Loc,bool * Invalid)122541e66291SRichard Smith static bool isInvalid(LocType Loc, bool *Invalid) {
1226ea6d7f33SZhanyong Wan bool MyInvalid = Loc.isInvalid();
1227ea6d7f33SZhanyong Wan if (Invalid)
1228ea6d7f33SZhanyong Wan *Invalid = MyInvalid;
1229ea6d7f33SZhanyong Wan return MyInvalid;
1230ea6d7f33SZhanyong Wan }
1231ea6d7f33SZhanyong Wan
getSpellingColumnNumber(SourceLocation Loc,bool * Invalid) const12327bda4b83SDouglas Gregor unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc,
12337bda4b83SDouglas Gregor bool *Invalid) const {
1234ea6d7f33SZhanyong Wan if (isInvalid(Loc, Invalid)) return 0;
1235e4ad4176SChris Lattner std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
12367bda4b83SDouglas Gregor return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
1237e4ad4176SChris Lattner }
1238e4ad4176SChris Lattner
getExpansionColumnNumber(SourceLocation Loc,bool * Invalid) const123942f35f9cSChandler Carruth unsigned SourceManager::getExpansionColumnNumber(SourceLocation Loc,
12407bda4b83SDouglas Gregor bool *Invalid) const {
1241ea6d7f33SZhanyong Wan if (isInvalid(Loc, Invalid)) return 0;
1242c7ca5218SChandler Carruth std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
12437bda4b83SDouglas Gregor return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
1244e4ad4176SChris Lattner }
1245e4ad4176SChris Lattner
getPresumedColumnNumber(SourceLocation Loc,bool * Invalid) const12461aef0c56SChandler Carruth unsigned SourceManager::getPresumedColumnNumber(SourceLocation Loc,
12471aef0c56SChandler Carruth bool *Invalid) const {
124841e66291SRichard Smith PresumedLoc PLoc = getPresumedLoc(Loc);
124941e66291SRichard Smith if (isInvalid(PLoc, Invalid)) return 0;
125041e66291SRichard Smith return PLoc.getColumn();
12511aef0c56SChandler Carruth }
12521aef0c56SChandler Carruth
125320105b6bSserge-sans-paille // Check if mutli-byte word x has bytes between m and n, included. This may also
125420105b6bSserge-sans-paille // catch bytes equal to n + 1.
125520105b6bSserge-sans-paille // The returned value holds a 0x80 at each byte position that holds a match.
125620105b6bSserge-sans-paille // see http://graphics.stanford.edu/~seander/bithacks.html#HasBetweenInWord
125720105b6bSserge-sans-paille template <class T>
likelyhasbetween(T x,unsigned char m,unsigned char n)125820105b6bSserge-sans-paille static constexpr inline T likelyhasbetween(T x, unsigned char m,
125920105b6bSserge-sans-paille unsigned char n) {
126020105b6bSserge-sans-paille return ((x - ~static_cast<T>(0) / 255 * (n + 1)) & ~x &
1261ca55f051SYang Fan ((x & ~static_cast<T>(0) / 255 * 127) +
1262ca55f051SYang Fan (~static_cast<T>(0) / 255 * (127 - (m - 1))))) &
126320105b6bSserge-sans-paille ~static_cast<T>(0) / 255 * 128;
126420105b6bSserge-sans-paille }
1265543036a4SBenjamin Kramer
get(llvm::MemoryBufferRef Buffer,llvm::BumpPtrAllocator & Alloc)1266dbbc4f4eSDuncan P. N. Exon Smith LineOffsetMapping LineOffsetMapping::get(llvm::MemoryBufferRef Buffer,
1267dbbc4f4eSDuncan P. N. Exon Smith llvm::BumpPtrAllocator &Alloc) {
126820105b6bSserge-sans-paille
12697a51313dSChris Lattner // Find the file offsets of all of the *physical* source lines. This does
12707a51313dSChris Lattner // not look at trigraphs, escaped newlines, or anything else tricky.
12710e62c1ccSChris Lattner SmallVector<unsigned, 256> LineOffsets;
12727a51313dSChris Lattner
12737a51313dSChris Lattner // Line #1 starts at char 0.
12747a51313dSChris Lattner LineOffsets.push_back(0);
12757a51313dSChris Lattner
1276dbbc4f4eSDuncan P. N. Exon Smith const unsigned char *Buf = (const unsigned char *)Buffer.getBufferStart();
1277dbbc4f4eSDuncan P. N. Exon Smith const unsigned char *End = (const unsigned char *)Buffer.getBufferEnd();
1278f28972faSJan Korous const std::size_t BufLen = End - Buf;
127920105b6bSserge-sans-paille
1280d906e731SFangrui Song unsigned I = 0;
128120105b6bSserge-sans-paille uint64_t Word;
128220105b6bSserge-sans-paille
128320105b6bSserge-sans-paille // scan sizeof(Word) bytes at a time for new lines.
128420105b6bSserge-sans-paille // This is much faster than scanning each byte independently.
128520105b6bSserge-sans-paille if (BufLen > sizeof(Word)) {
128620105b6bSserge-sans-paille do {
128720105b6bSserge-sans-paille Word = llvm::support::endian::read64(Buf + I, llvm::support::little);
128820105b6bSserge-sans-paille // no new line => jump over sizeof(Word) bytes.
128920105b6bSserge-sans-paille auto Mask = likelyhasbetween(Word, '\n', '\r');
129020105b6bSserge-sans-paille if (!Mask) {
129120105b6bSserge-sans-paille I += sizeof(Word);
129220105b6bSserge-sans-paille continue;
129320105b6bSserge-sans-paille }
129420105b6bSserge-sans-paille
129520105b6bSserge-sans-paille // At that point, Mask contains 0x80 set at each byte that holds a value
129620105b6bSserge-sans-paille // in [\n, \r + 1 [
129720105b6bSserge-sans-paille
129820105b6bSserge-sans-paille // Scan for the next newline - it's very likely there's one.
129920105b6bSserge-sans-paille unsigned N =
130020105b6bSserge-sans-paille llvm::countTrailingZeros(Mask) - 7; // -7 because 0x80 is the marker
130120105b6bSserge-sans-paille Word >>= N;
130220105b6bSserge-sans-paille I += N / 8 + 1;
130320105b6bSserge-sans-paille unsigned char Byte = Word;
130420105b6bSserge-sans-paille if (Byte == '\n') {
130520105b6bSserge-sans-paille LineOffsets.push_back(I);
130620105b6bSserge-sans-paille } else if (Byte == '\r') {
130720105b6bSserge-sans-paille // If this is \r\n, skip both characters.
130820105b6bSserge-sans-paille if (Buf[I] == '\n')
130920105b6bSserge-sans-paille ++I;
131020105b6bSserge-sans-paille LineOffsets.push_back(I);
131120105b6bSserge-sans-paille }
131220105b6bSserge-sans-paille } while (I < BufLen - sizeof(Word) - 1);
131320105b6bSserge-sans-paille }
131420105b6bSserge-sans-paille
131520105b6bSserge-sans-paille // Handle tail using a regular check.
1316f28972faSJan Korous while (I < BufLen) {
1317f28972faSJan Korous if (Buf[I] == '\n') {
1318f28972faSJan Korous LineOffsets.push_back(I + 1);
1319f28972faSJan Korous } else if (Buf[I] == '\r') {
1320d906e731SFangrui Song // If this is \r\n, skip both characters.
1321f28972faSJan Korous if (I + 1 < BufLen && Buf[I + 1] == '\n')
1322d906e731SFangrui Song ++I;
1323f28972faSJan Korous LineOffsets.push_back(I + 1);
13247a51313dSChris Lattner }
1325f28972faSJan Korous ++I;
13267a51313dSChris Lattner }
13277a51313dSChris Lattner
1328dbbc4f4eSDuncan P. N. Exon Smith return LineOffsetMapping(LineOffsets, Alloc);
1329dbbc4f4eSDuncan P. N. Exon Smith }
1330dbbc4f4eSDuncan P. N. Exon Smith
LineOffsetMapping(ArrayRef<unsigned> LineOffsets,llvm::BumpPtrAllocator & Alloc)1331dbbc4f4eSDuncan P. N. Exon Smith LineOffsetMapping::LineOffsetMapping(ArrayRef<unsigned> LineOffsets,
1332dbbc4f4eSDuncan P. N. Exon Smith llvm::BumpPtrAllocator &Alloc)
1333dbbc4f4eSDuncan P. N. Exon Smith : Storage(Alloc.Allocate<unsigned>(LineOffsets.size() + 1)) {
1334dbbc4f4eSDuncan P. N. Exon Smith Storage[0] = LineOffsets.size();
1335dbbc4f4eSDuncan P. N. Exon Smith std::copy(LineOffsets.begin(), LineOffsets.end(), Storage + 1);
13367a51313dSChris Lattner }
13377a51313dSChris Lattner
133853e384f6SChris Lattner /// getLineNumber - Given a SourceLocation, return the spelling line number
13397a51313dSChris Lattner /// for the position indicated. This requires building and caching a table of
13407a51313dSChris Lattner /// line offsets for the MemoryBuffer, so this is not cheap: use only when
13417a51313dSChris Lattner /// about to emit a diagnostic.
getLineNumber(FileID FID,unsigned FilePos,bool * Invalid) const13427bda4b83SDouglas Gregor unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
13437bda4b83SDouglas Gregor bool *Invalid) const {
1344f15eac11SArgyrios Kyrtzidis if (FID.isInvalid()) {
1345f15eac11SArgyrios Kyrtzidis if (Invalid)
1346f15eac11SArgyrios Kyrtzidis *Invalid = true;
1347f15eac11SArgyrios Kyrtzidis return 1;
1348f15eac11SArgyrios Kyrtzidis }
1349f15eac11SArgyrios Kyrtzidis
13505431c37bSDuncan P. N. Exon Smith const ContentCache *Content;
135188ea93e6SChris Lattner if (LastLineNoFileIDQuery == FID)
13527a51313dSChris Lattner Content = LastLineNoContentCache;
135349f754f4SDouglas Gregor else {
135449f754f4SDouglas Gregor bool MyInvalid = false;
135549f754f4SDouglas Gregor const SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
135649f754f4SDouglas Gregor if (MyInvalid || !Entry.isFile()) {
135749f754f4SDouglas Gregor if (Invalid)
135849f754f4SDouglas Gregor *Invalid = true;
135949f754f4SDouglas Gregor return 1;
136049f754f4SDouglas Gregor }
136149f754f4SDouglas Gregor
13625431c37bSDuncan P. N. Exon Smith Content = &Entry.getFile().getContentCache();
136349f754f4SDouglas Gregor }
13647a51313dSChris Lattner
13657a51313dSChris Lattner // If this is the first use of line information for this buffer, compute the
13667a51313dSChris Lattner /// SourceLineCache for it on demand.
1367f1186c5aSCraig Topper if (!Content->SourceLineCache) {
1368cf52a85dSDuncan P. N. Exon Smith llvm::Optional<llvm::MemoryBufferRef> Buffer =
1369cf52a85dSDuncan P. N. Exon Smith Content->getBufferOrNone(Diag, getFileManager(), SourceLocation());
13707bda4b83SDouglas Gregor if (Invalid)
1371cf52a85dSDuncan P. N. Exon Smith *Invalid = !Buffer;
1372cf52a85dSDuncan P. N. Exon Smith if (!Buffer)
13737bda4b83SDouglas Gregor return 1;
1374cf52a85dSDuncan P. N. Exon Smith
1375cf52a85dSDuncan P. N. Exon Smith Content->SourceLineCache =
1376cf52a85dSDuncan P. N. Exon Smith LineOffsetMapping::get(*Buffer, ContentCacheAlloc);
13777bda4b83SDouglas Gregor } else if (Invalid)
13787bda4b83SDouglas Gregor *Invalid = false;
13797a51313dSChris Lattner
13807a51313dSChris Lattner // Okay, we know we have a line number table. Do a binary search to find the
13817a51313dSChris Lattner // line number that this character position lands on.
1382dbbc4f4eSDuncan P. N. Exon Smith const unsigned *SourceLineCache = Content->SourceLineCache.begin();
1383dbbc4f4eSDuncan P. N. Exon Smith const unsigned *SourceLineCacheStart = SourceLineCache;
1384dbbc4f4eSDuncan P. N. Exon Smith const unsigned *SourceLineCacheEnd = Content->SourceLineCache.end();
13857a51313dSChris Lattner
138688ea93e6SChris Lattner unsigned QueriedFilePos = FilePos+1;
13877a51313dSChris Lattner
138870f924dfSDaniel Dunbar // FIXME: I would like to be convinced that this code is worth being as
138970f924dfSDaniel Dunbar // complicated as it is, binary search isn't that slow.
139070f924dfSDaniel Dunbar //
139170f924dfSDaniel Dunbar // If it is worth being optimized, then in my opinion it could be more
139270f924dfSDaniel Dunbar // performant, simpler, and more obviously correct by just "galloping" outward
139370f924dfSDaniel Dunbar // from the queried file position. In fact, this could be incorporated into a
139470f924dfSDaniel Dunbar // generic algorithm such as lower_bound_with_hint.
139570f924dfSDaniel Dunbar //
139670f924dfSDaniel Dunbar // If someone gives me a test case where this matters, and I will do it! - DWD
139770f924dfSDaniel Dunbar
13987a51313dSChris Lattner // If the previous query was to the same file, we know both the file pos from
13997a51313dSChris Lattner // that query and the line number returned. This allows us to narrow the
14007a51313dSChris Lattner // search space from the entire file to something near the match.
140188ea93e6SChris Lattner if (LastLineNoFileIDQuery == FID) {
14027a51313dSChris Lattner if (QueriedFilePos >= LastLineNoFilePos) {
140370f924dfSDaniel Dunbar // FIXME: Potential overflow?
14047a51313dSChris Lattner SourceLineCache = SourceLineCache+LastLineNoResult-1;
14057a51313dSChris Lattner
14067a51313dSChris Lattner // The query is likely to be nearby the previous one. Here we check to
14077a51313dSChris Lattner // see if it is within 5, 10 or 20 lines. It can be far away in cases
14087a51313dSChris Lattner // where big comment blocks and vertical whitespace eat up lines but
14097a51313dSChris Lattner // contribute no tokens.
14107a51313dSChris Lattner if (SourceLineCache+5 < SourceLineCacheEnd) {
14117a51313dSChris Lattner if (SourceLineCache[5] > QueriedFilePos)
14127a51313dSChris Lattner SourceLineCacheEnd = SourceLineCache+5;
14137a51313dSChris Lattner else if (SourceLineCache+10 < SourceLineCacheEnd) {
14147a51313dSChris Lattner if (SourceLineCache[10] > QueriedFilePos)
14157a51313dSChris Lattner SourceLineCacheEnd = SourceLineCache+10;
14167a51313dSChris Lattner else if (SourceLineCache+20 < SourceLineCacheEnd) {
14177a51313dSChris Lattner if (SourceLineCache[20] > QueriedFilePos)
14187a51313dSChris Lattner SourceLineCacheEnd = SourceLineCache+20;
14197a51313dSChris Lattner }
14207a51313dSChris Lattner }
14217a51313dSChris Lattner }
14227a51313dSChris Lattner } else {
1423dbbc4f4eSDuncan P. N. Exon Smith if (LastLineNoResult < Content->SourceLineCache.size())
14247a51313dSChris Lattner SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1;
14257a51313dSChris Lattner }
14267a51313dSChris Lattner }
14277a51313dSChris Lattner
1428dbbc4f4eSDuncan P. N. Exon Smith const unsigned *Pos =
1429dbbc4f4eSDuncan P. N. Exon Smith std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos);
14307a51313dSChris Lattner unsigned LineNo = Pos-SourceLineCacheStart;
14317a51313dSChris Lattner
143288ea93e6SChris Lattner LastLineNoFileIDQuery = FID;
14337a51313dSChris Lattner LastLineNoContentCache = Content;
14347a51313dSChris Lattner LastLineNoFilePos = QueriedFilePos;
14357a51313dSChris Lattner LastLineNoResult = LineNo;
14367a51313dSChris Lattner return LineNo;
14377a51313dSChris Lattner }
14387a51313dSChris Lattner
getSpellingLineNumber(SourceLocation Loc,bool * Invalid) const14391aef0c56SChandler Carruth unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc,
14401aef0c56SChandler Carruth bool *Invalid) const {
14411aef0c56SChandler Carruth if (isInvalid(Loc, Invalid)) return 0;
14421aef0c56SChandler Carruth std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
14431aef0c56SChandler Carruth return getLineNumber(LocInfo.first, LocInfo.second);
14441aef0c56SChandler Carruth }
getExpansionLineNumber(SourceLocation Loc,bool * Invalid) const1445d48db211SChandler Carruth unsigned SourceManager::getExpansionLineNumber(SourceLocation Loc,
14467bda4b83SDouglas Gregor bool *Invalid) const {
1447ea6d7f33SZhanyong Wan if (isInvalid(Loc, Invalid)) return 0;
1448c7ca5218SChandler Carruth std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
144988ea93e6SChris Lattner return getLineNumber(LocInfo.first, LocInfo.second);
145088ea93e6SChris Lattner }
getPresumedLineNumber(SourceLocation Loc,bool * Invalid) const14511aef0c56SChandler Carruth unsigned SourceManager::getPresumedLineNumber(SourceLocation Loc,
14527bda4b83SDouglas Gregor bool *Invalid) const {
14539c52767fSRichard Smith PresumedLoc PLoc = getPresumedLoc(Loc);
14549c52767fSRichard Smith if (isInvalid(PLoc, Invalid)) return 0;
14559c52767fSRichard Smith return PLoc.getLine();
145688ea93e6SChris Lattner }
145788ea93e6SChris Lattner
145895d9c5e7SChris Lattner /// getFileCharacteristic - return the file characteristic of the specified
145995d9c5e7SChris Lattner /// source location, indicating whether this is a normal file, a system
146095d9c5e7SChris Lattner /// header, or an "implicit extern C" system header.
146195d9c5e7SChris Lattner ///
146295d9c5e7SChris Lattner /// This state can be modified with flags on GNU linemarker directives like:
146395d9c5e7SChris Lattner /// # 4 "foo.h" 3
146495d9c5e7SChris Lattner /// which changes all source locations in the current file after that to be
146595d9c5e7SChris Lattner /// considered to be from a system header.
146695d9c5e7SChris Lattner SrcMgr::CharacteristicKind
getFileCharacteristic(SourceLocation Loc) const146795d9c5e7SChris Lattner SourceManager::getFileCharacteristic(SourceLocation Loc) const {
14688b563665SYaron Keren assert(Loc.isValid() && "Can't get file characteristic of invalid loc!");
1469c7ca5218SChandler Carruth std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
1470b6c6daa9SDuncan P. N. Exon Smith const SLocEntry *SEntry = getSLocEntryForFile(LocInfo.first);
1471b6c6daa9SDuncan P. N. Exon Smith if (!SEntry)
147249f754f4SDouglas Gregor return C_User;
147349f754f4SDouglas Gregor
1474b6c6daa9SDuncan P. N. Exon Smith const SrcMgr::FileInfo &FI = SEntry->getFile();
147595d9c5e7SChris Lattner
147695d9c5e7SChris Lattner // If there are no #line directives in this file, just return the whole-file
147795d9c5e7SChris Lattner // state.
147895d9c5e7SChris Lattner if (!FI.hasLineDirectives())
147995d9c5e7SChris Lattner return FI.getFileCharacteristic();
148095d9c5e7SChris Lattner
148195d9c5e7SChris Lattner assert(LineTable && "Can't have linetable entries without a LineTable!");
148295d9c5e7SChris Lattner // See if there is a #line directive before the location.
148395d9c5e7SChris Lattner const LineEntry *Entry =
148402c2dbf4SDouglas Gregor LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second);
148595d9c5e7SChris Lattner
148695d9c5e7SChris Lattner // If this is before the first line marker, use the file characteristic.
148795d9c5e7SChris Lattner if (!Entry)
148895d9c5e7SChris Lattner return FI.getFileCharacteristic();
148995d9c5e7SChris Lattner
149095d9c5e7SChris Lattner return Entry->FileKind;
149195d9c5e7SChris Lattner }
149295d9c5e7SChris Lattner
1493a6f037ceSChris Lattner /// Return the filename or buffer identifier of the buffer the location is in.
149487a2acf1SJames Dennett /// Note that this name does not respect \#line directives. Use getPresumedLoc
1495a6f037ceSChris Lattner /// for normal clients.
getBufferName(SourceLocation Loc,bool * Invalid) const149699d1b295SMehdi Amini StringRef SourceManager::getBufferName(SourceLocation Loc,
14977bda4b83SDouglas Gregor bool *Invalid) const {
1498ea6d7f33SZhanyong Wan if (isInvalid(Loc, Invalid)) return "<invalid loc>";
1499a6f037ceSChris Lattner
150054c1bcabSDuncan P. N. Exon Smith auto B = getBufferOrNone(getFileID(Loc));
150154c1bcabSDuncan P. N. Exon Smith if (Invalid)
150254c1bcabSDuncan P. N. Exon Smith *Invalid = !B;
150354c1bcabSDuncan P. N. Exon Smith return B ? B->getBufferIdentifier() : "<invalid buffer>";
1504a6f037ceSChris Lattner }
1505a6f037ceSChris Lattner
1506f1ca7d3eSChris Lattner /// getPresumedLoc - This method returns the "presumed" location of a
150787a2acf1SJames Dennett /// SourceLocation specifies. A "presumed location" can be modified by \#line
1508f1ca7d3eSChris Lattner /// or GNU line marker directives. This provides a view on the data that a
1509f1ca7d3eSChris Lattner /// user should see in diagnostics, for example.
1510f1ca7d3eSChris Lattner ///
151164ee782eSChandler Carruth /// Note that a presumed location is always given as the expansion point of an
151264ee782eSChandler Carruth /// expansion location, not at the spelling location.
getPresumedLoc(SourceLocation Loc,bool UseLineDirectives) const15130b50cb79SRichard Smith PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc,
15140b50cb79SRichard Smith bool UseLineDirectives) const {
1515f1ca7d3eSChris Lattner if (Loc.isInvalid()) return PresumedLoc();
15164fa23625SChris Lattner
151764ee782eSChandler Carruth // Presumed locations are always for expansion points.
1518c7ca5218SChandler Carruth std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
1519f1ca7d3eSChris Lattner
152049f754f4SDouglas Gregor bool Invalid = false;
152149f754f4SDouglas Gregor const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
152249f754f4SDouglas Gregor if (Invalid || !Entry.isFile())
152349f754f4SDouglas Gregor return PresumedLoc();
152449f754f4SDouglas Gregor
152549f754f4SDouglas Gregor const SrcMgr::FileInfo &FI = Entry.getFile();
152674a87834SDuncan P. N. Exon Smith const SrcMgr::ContentCache *C = &FI.getContentCache();
15274fa23625SChris Lattner
1528d4293922SChris Lattner // To get the source name, first consult the FileEntry (if one exists)
1529d4293922SChris Lattner // before the MemBuffer as this will avoid unnecessarily paging in the
1530d4293922SChris Lattner // MemBuffer.
1531047e65dbSAlexandre Ganea FileID FID = LocInfo.first;
153299d1b295SMehdi Amini StringRef Filename;
153311e6f0a6SArgyrios Kyrtzidis if (C->OrigEntry)
153411e6f0a6SArgyrios Kyrtzidis Filename = C->OrigEntry->getName();
1535d758f79eSDuncan P. N. Exon Smith else if (auto Buffer = C->getBufferOrNone(Diag, getFileManager()))
1536d758f79eSDuncan P. N. Exon Smith Filename = Buffer->getBufferIdentifier();
153749f754f4SDouglas Gregor
153875f26d6cSDouglas Gregor unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid);
153975f26d6cSDouglas Gregor if (Invalid)
154075f26d6cSDouglas Gregor return PresumedLoc();
154175f26d6cSDouglas Gregor unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second, &Invalid);
154275f26d6cSDouglas Gregor if (Invalid)
154375f26d6cSDouglas Gregor return PresumedLoc();
154475f26d6cSDouglas Gregor
1545d4293922SChris Lattner SourceLocation IncludeLoc = FI.getIncludeLoc();
1546f1ca7d3eSChris Lattner
1547d4293922SChris Lattner // If we have #line directives in this file, update and overwrite the physical
1548d4293922SChris Lattner // location info if appropriate.
15490b50cb79SRichard Smith if (UseLineDirectives && FI.hasLineDirectives()) {
1550d4293922SChris Lattner assert(LineTable && "Can't have linetable entries without a LineTable!");
1551d4293922SChris Lattner // See if there is a #line directive before this. If so, get it.
1552d4293922SChris Lattner if (const LineEntry *Entry =
155302c2dbf4SDouglas Gregor LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second)) {
1554c1219ff7SChris Lattner // If the LineEntry indicates a filename, use it.
1555047e65dbSAlexandre Ganea if (Entry->FilenameID != -1) {
1556d4293922SChris Lattner Filename = LineTable->getFilename(Entry->FilenameID);
1557047e65dbSAlexandre Ganea // The contents of files referenced by #line are not in the
1558047e65dbSAlexandre Ganea // SourceManager
1559047e65dbSAlexandre Ganea FID = FileID::get(0);
1560047e65dbSAlexandre Ganea }
1561c1219ff7SChris Lattner
1562c1219ff7SChris Lattner // Use the line number specified by the LineEntry. This line number may
1563c1219ff7SChris Lattner // be multiple lines down from the line entry. Add the difference in
1564c1219ff7SChris Lattner // physical line numbers from the query point and the line marker to the
1565c1219ff7SChris Lattner // total.
1566c1219ff7SChris Lattner unsigned MarkerLineNo = getLineNumber(LocInfo.first, Entry->FileOffset);
1567c1219ff7SChris Lattner LineNo = Entry->LineNo + (LineNo-MarkerLineNo-1);
1568c1219ff7SChris Lattner
156920c50ba2SChris Lattner // Note that column numbers are not molested by line markers.
15701c967784SChris Lattner
15711c967784SChris Lattner // Handle virtual #include manipulation.
15721c967784SChris Lattner if (Entry->IncludeOffset) {
15731c967784SChris Lattner IncludeLoc = getLocForStartOfFile(LocInfo.first);
1574e6e67deeSArgyrios Kyrtzidis IncludeLoc = IncludeLoc.getLocWithOffset(Entry->IncludeOffset);
15751c967784SChris Lattner }
1576d4293922SChris Lattner }
1577d4293922SChris Lattner }
1578d4293922SChris Lattner
1579047e65dbSAlexandre Ganea return PresumedLoc(Filename.data(), FID, LineNo, ColNo, IncludeLoc);
15804fa23625SChris Lattner }
15814fa23625SChris Lattner
15829fc8faf9SAdrian Prantl /// Returns whether the PresumedLoc for a given SourceLocation is
1583e7800df4SBenjamin Kramer /// in the main file.
1584e7800df4SBenjamin Kramer ///
1585e7800df4SBenjamin Kramer /// This computes the "presumed" location for a SourceLocation, then checks
1586e7800df4SBenjamin Kramer /// whether it came from a file other than the main file. This is different
1587e7800df4SBenjamin Kramer /// from isWrittenInMainFile() because it takes line marker directives into
1588e7800df4SBenjamin Kramer /// account.
isInMainFile(SourceLocation Loc) const1589e7800df4SBenjamin Kramer bool SourceManager::isInMainFile(SourceLocation Loc) const {
1590e7800df4SBenjamin Kramer if (Loc.isInvalid()) return false;
1591e7800df4SBenjamin Kramer
1592e7800df4SBenjamin Kramer // Presumed locations are always for expansion points.
1593e7800df4SBenjamin Kramer std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
1594e7800df4SBenjamin Kramer
1595b6c6daa9SDuncan P. N. Exon Smith const SLocEntry *Entry = getSLocEntryForFile(LocInfo.first);
1596b6c6daa9SDuncan P. N. Exon Smith if (!Entry)
1597e7800df4SBenjamin Kramer return false;
1598e7800df4SBenjamin Kramer
1599b6c6daa9SDuncan P. N. Exon Smith const SrcMgr::FileInfo &FI = Entry->getFile();
1600e7800df4SBenjamin Kramer
1601e7800df4SBenjamin Kramer // Check if there is a line directive for this location.
1602e7800df4SBenjamin Kramer if (FI.hasLineDirectives())
1603e7800df4SBenjamin Kramer if (const LineEntry *Entry =
1604e7800df4SBenjamin Kramer LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second))
1605e7800df4SBenjamin Kramer if (Entry->IncludeOffset)
1606e7800df4SBenjamin Kramer return false;
1607e7800df4SBenjamin Kramer
1608e7800df4SBenjamin Kramer return FI.getIncludeLoc().isInvalid();
1609e7800df4SBenjamin Kramer }
1610e7800df4SBenjamin Kramer
16119fc8faf9SAdrian Prantl /// The size of the SLocEntry that \p FID represents.
getFileIDSize(FileID FID) const1612296374b5SArgyrios Kyrtzidis unsigned SourceManager::getFileIDSize(FileID FID) const {
1613296374b5SArgyrios Kyrtzidis bool Invalid = false;
1614296374b5SArgyrios Kyrtzidis const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
1615296374b5SArgyrios Kyrtzidis if (Invalid)
1616296374b5SArgyrios Kyrtzidis return 0;
1617296374b5SArgyrios Kyrtzidis
1618296374b5SArgyrios Kyrtzidis int ID = FID.ID;
161921401a72SSimon Tatham SourceLocation::UIntTy NextOffset;
1620296374b5SArgyrios Kyrtzidis if ((ID > 0 && unsigned(ID+1) == local_sloc_entry_size()))
1621296374b5SArgyrios Kyrtzidis NextOffset = getNextLocalOffset();
1622296374b5SArgyrios Kyrtzidis else if (ID+1 == -1)
1623296374b5SArgyrios Kyrtzidis NextOffset = MaxLoadedOffset;
1624296374b5SArgyrios Kyrtzidis else
1625296374b5SArgyrios Kyrtzidis NextOffset = getSLocEntry(FileID::get(ID+1)).getOffset();
1626296374b5SArgyrios Kyrtzidis
1627296374b5SArgyrios Kyrtzidis return NextOffset - Entry.getOffset() - 1;
1628296374b5SArgyrios Kyrtzidis }
1629296374b5SArgyrios Kyrtzidis
16304fa23625SChris Lattner //===----------------------------------------------------------------------===//
16314fa23625SChris Lattner // Other miscellaneous methods.
16324fa23625SChris Lattner //===----------------------------------------------------------------------===//
16334fa23625SChris Lattner
16349fc8faf9SAdrian Prantl /// Get the source location for the given file:line:col triplet.
163588f663c0SArgyrios Kyrtzidis ///
163688f663c0SArgyrios Kyrtzidis /// If the source file is included multiple times, the source location will
1637925296b4SDouglas Gregor /// be based upon an arbitrary inclusion.
translateFileLineCol(const FileEntry * SourceFile,unsigned Line,unsigned Col) const163892a47bd9SArgyrios Kyrtzidis SourceLocation SourceManager::translateFileLineCol(const FileEntry *SourceFile,
16397c06d866SArgyrios Kyrtzidis unsigned Line,
16407c06d866SArgyrios Kyrtzidis unsigned Col) const {
164188f663c0SArgyrios Kyrtzidis assert(SourceFile && "Null source file!");
164288f663c0SArgyrios Kyrtzidis assert(Line && Col && "Line and column should start from 1!");
164388f663c0SArgyrios Kyrtzidis
164404a6e5f8SArgyrios Kyrtzidis FileID FirstFID = translateFile(SourceFile);
164504a6e5f8SArgyrios Kyrtzidis return translateLineCol(FirstFID, Line, Col);
164604a6e5f8SArgyrios Kyrtzidis }
164704a6e5f8SArgyrios Kyrtzidis
16489fc8faf9SAdrian Prantl /// Get the FileID for the given file.
164904a6e5f8SArgyrios Kyrtzidis ///
165004a6e5f8SArgyrios Kyrtzidis /// If the source file is included multiple times, the FileID will be the
165104a6e5f8SArgyrios Kyrtzidis /// first inclusion.
translateFile(const FileEntry * SourceFile) const165204a6e5f8SArgyrios Kyrtzidis FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
165304a6e5f8SArgyrios Kyrtzidis assert(SourceFile && "Null source file!");
165404a6e5f8SArgyrios Kyrtzidis
1655e664276bSDouglas Gregor // First, check the main file ID, since it is common to look for a
1656e664276bSDouglas Gregor // location in the main file.
16578b563665SYaron Keren if (MainFileID.isValid()) {
165849f754f4SDouglas Gregor bool Invalid = false;
165949f754f4SDouglas Gregor const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid);
166049f754f4SDouglas Gregor if (Invalid)
166104a6e5f8SArgyrios Kyrtzidis return FileID();
166249f754f4SDouglas Gregor
1663e664276bSDouglas Gregor if (MainSLoc.isFile()) {
166474a87834SDuncan P. N. Exon Smith if (MainSLoc.getFile().getContentCache().OrigEntry == SourceFile)
166506abd696SAlex Lorenz return MainFileID;
1666d766be68SDouglas Gregor }
1667d766be68SDouglas Gregor }
1668e664276bSDouglas Gregor
1669e664276bSDouglas Gregor // The location we're looking for isn't in the main file; look
1670925296b4SDouglas Gregor // through all of the local source locations.
1671925296b4SDouglas Gregor for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) {
16728cce7af0SNick Desaulniers const SLocEntry &SLoc = getLocalSLocEntry(I);
167374a87834SDuncan P. N. Exon Smith if (SLoc.isFile() &&
167474a87834SDuncan P. N. Exon Smith SLoc.getFile().getContentCache().OrigEntry == SourceFile)
167506abd696SAlex Lorenz return FileID::get(I);
1676e664276bSDouglas Gregor }
167706abd696SAlex Lorenz
1678925296b4SDouglas Gregor // If that still didn't help, try the modules.
1679925296b4SDouglas Gregor for (unsigned I = 0, N = loaded_sloc_entry_size(); I != N; ++I) {
1680925296b4SDouglas Gregor const SLocEntry &SLoc = getLoadedSLocEntry(I);
168174a87834SDuncan P. N. Exon Smith if (SLoc.isFile() &&
168274a87834SDuncan P. N. Exon Smith SLoc.getFile().getContentCache().OrigEntry == SourceFile)
168306abd696SAlex Lorenz return FileID::get(-int(I) - 2);
1684e664276bSDouglas Gregor }
1685e664276bSDouglas Gregor
168604a6e5f8SArgyrios Kyrtzidis return FileID();
1687532c5196SArgyrios Kyrtzidis }
1688532c5196SArgyrios Kyrtzidis
16899fc8faf9SAdrian Prantl /// Get the source location in \arg FID for the given line:col.
1690532c5196SArgyrios Kyrtzidis /// Returns null location if \arg FID is not a file SLocEntry.
translateLineCol(FileID FID,unsigned Line,unsigned Col) const1691532c5196SArgyrios Kyrtzidis SourceLocation SourceManager::translateLineCol(FileID FID,
16927c06d866SArgyrios Kyrtzidis unsigned Line,
16937c06d866SArgyrios Kyrtzidis unsigned Col) const {
1694ef1cf830SAaron Ballman // Lines are used as a one-based index into a zero-based array. This assert
1695ef1cf830SAaron Ballman // checks for possible buffer underruns.
1696fe2c0ff9SGabor Horvath assert(Line && Col && "Line and column should start from 1!");
1697ef1cf830SAaron Ballman
1698532c5196SArgyrios Kyrtzidis if (FID.isInvalid())
1699532c5196SArgyrios Kyrtzidis return SourceLocation();
1700532c5196SArgyrios Kyrtzidis
1701532c5196SArgyrios Kyrtzidis bool Invalid = false;
1702532c5196SArgyrios Kyrtzidis const SLocEntry &Entry = getSLocEntry(FID, &Invalid);
1703532c5196SArgyrios Kyrtzidis if (Invalid)
1704532c5196SArgyrios Kyrtzidis return SourceLocation();
1705532c5196SArgyrios Kyrtzidis
1706532c5196SArgyrios Kyrtzidis if (!Entry.isFile())
170788f663c0SArgyrios Kyrtzidis return SourceLocation();
1708e664276bSDouglas Gregor
17097c2b28a1SArgyrios Kyrtzidis SourceLocation FileLoc = SourceLocation::getFileLoc(Entry.getOffset());
17107c2b28a1SArgyrios Kyrtzidis
1711e664276bSDouglas Gregor if (Line == 1 && Col == 1)
17127c2b28a1SArgyrios Kyrtzidis return FileLoc;
1713e664276bSDouglas Gregor
17145431c37bSDuncan P. N. Exon Smith const ContentCache *Content = &Entry.getFile().getContentCache();
171588f663c0SArgyrios Kyrtzidis
171688f663c0SArgyrios Kyrtzidis // If this is the first use of line information for this buffer, compute the
1717925296b4SDouglas Gregor // SourceLineCache for it on demand.
1718d758f79eSDuncan P. N. Exon Smith llvm::Optional<llvm::MemoryBufferRef> Buffer =
1719d758f79eSDuncan P. N. Exon Smith Content->getBufferOrNone(Diag, getFileManager());
1720d758f79eSDuncan P. N. Exon Smith if (!Buffer)
1721d758f79eSDuncan P. N. Exon Smith return SourceLocation();
1722cf52a85dSDuncan P. N. Exon Smith if (!Content->SourceLineCache)
1723cf52a85dSDuncan P. N. Exon Smith Content->SourceLineCache =
1724cf52a85dSDuncan P. N. Exon Smith LineOffsetMapping::get(*Buffer, ContentCacheAlloc);
1725d758f79eSDuncan P. N. Exon Smith
1726dbbc4f4eSDuncan P. N. Exon Smith if (Line > Content->SourceLineCache.size()) {
1727d758f79eSDuncan P. N. Exon Smith unsigned Size = Buffer->getBufferSize();
1728b8b9f28eSDouglas Gregor if (Size > 0)
1729b8b9f28eSDouglas Gregor --Size;
17307c2b28a1SArgyrios Kyrtzidis return FileLoc.getLocWithOffset(Size);
1731b8b9f28eSDouglas Gregor }
1732b8b9f28eSDouglas Gregor
1733b8b9f28eSDouglas Gregor unsigned FilePos = Content->SourceLineCache[Line - 1];
17342a8bc152SDylan Noblesmith const char *Buf = Buffer->getBufferStart() + FilePos;
17352a8bc152SDylan Noblesmith unsigned BufLength = Buffer->getBufferSize() - FilePos;
17367c2b28a1SArgyrios Kyrtzidis if (BufLength == 0)
17377c2b28a1SArgyrios Kyrtzidis return FileLoc.getLocWithOffset(FilePos);
17387c2b28a1SArgyrios Kyrtzidis
1739b8b9f28eSDouglas Gregor unsigned i = 0;
1740b8b9f28eSDouglas Gregor
1741b8b9f28eSDouglas Gregor // Check that the given column is valid.
1742b8b9f28eSDouglas Gregor while (i < BufLength-1 && i < Col-1 && Buf[i] != '\n' && Buf[i] != '\r')
1743b8b9f28eSDouglas Gregor ++i;
17447c2b28a1SArgyrios Kyrtzidis return FileLoc.getLocWithOffset(FilePos + i);
174588f663c0SArgyrios Kyrtzidis }
174688f663c0SArgyrios Kyrtzidis
17479fc8faf9SAdrian Prantl /// Compute a map of macro argument chunks to their expanded source
174861ef3db2SArgyrios Kyrtzidis /// location. Chunks that are not part of a macro argument will map to an
174961ef3db2SArgyrios Kyrtzidis /// invalid source location. e.g. if a file contains one macro argument at
175061ef3db2SArgyrios Kyrtzidis /// offset 100 with length 10, this is how the map will be formed:
175161ef3db2SArgyrios Kyrtzidis /// 0 -> SourceLocation()
175261ef3db2SArgyrios Kyrtzidis /// 100 -> Expanded macro arg location
175361ef3db2SArgyrios Kyrtzidis /// 110 -> SourceLocation()
computeMacroArgsCache(MacroArgsMap & MacroArgsCache,FileID FID) const1754d2c6a6d1SVedant Kumar void SourceManager::computeMacroArgsCache(MacroArgsMap &MacroArgsCache,
17557c06d866SArgyrios Kyrtzidis FileID FID) const {
17568b563665SYaron Keren assert(FID.isValid());
175761ef3db2SArgyrios Kyrtzidis
175861ef3db2SArgyrios Kyrtzidis // Initially no macro argument chunk is present.
175961ef3db2SArgyrios Kyrtzidis MacroArgsCache.insert(std::make_pair(0, SourceLocation()));
176061ef3db2SArgyrios Kyrtzidis
176161ef3db2SArgyrios Kyrtzidis int ID = FID.ID;
1762918e0ca7SEugene Zelenko while (true) {
176361ef3db2SArgyrios Kyrtzidis ++ID;
176461ef3db2SArgyrios Kyrtzidis // Stop if there are no more FileIDs to check.
176561ef3db2SArgyrios Kyrtzidis if (ID > 0) {
176661ef3db2SArgyrios Kyrtzidis if (unsigned(ID) >= local_sloc_entry_size())
176761ef3db2SArgyrios Kyrtzidis return;
176861ef3db2SArgyrios Kyrtzidis } else if (ID == -1) {
176961ef3db2SArgyrios Kyrtzidis return;
177061ef3db2SArgyrios Kyrtzidis }
177161ef3db2SArgyrios Kyrtzidis
1772fe68302fSArgyrios Kyrtzidis bool Invalid = false;
1773fe68302fSArgyrios Kyrtzidis const SrcMgr::SLocEntry &Entry = getSLocEntryByID(ID, &Invalid);
1774fe68302fSArgyrios Kyrtzidis if (Invalid)
1775fe68302fSArgyrios Kyrtzidis return;
177661ef3db2SArgyrios Kyrtzidis if (Entry.isFile()) {
17778277a513SJan Korous auto& File = Entry.getFile();
1778e7870223SJan Korous if (File.getFileCharacteristic() == C_User_ModuleMap ||
1779e7870223SJan Korous File.getFileCharacteristic() == C_System_ModuleMap)
1780e7870223SJan Korous continue;
1781e7870223SJan Korous
1782e7870223SJan Korous SourceLocation IncludeLoc = File.getIncludeLoc();
1783411a254aSKadir Cetinkaya bool IncludedInFID =
1784411a254aSKadir Cetinkaya (IncludeLoc.isValid() && isInFileID(IncludeLoc, FID)) ||
1785411a254aSKadir Cetinkaya // Predefined header doesn't have a valid include location in main
1786411a254aSKadir Cetinkaya // file, but any files created by it should still be skipped when
1787411a254aSKadir Cetinkaya // computing macro args expanded in the main file.
178822e6b186SDuncan P. N. Exon Smith (FID == MainFileID && Entry.getFile().getName() == "<built-in>");
1789411a254aSKadir Cetinkaya if (IncludedInFID) {
1790411a254aSKadir Cetinkaya // Skip the files/macros of the #include'd file, we only care about
1791411a254aSKadir Cetinkaya // macros that lexed macro arguments from our file.
179261ef3db2SArgyrios Kyrtzidis if (Entry.getFile().NumCreatedFIDs)
179361ef3db2SArgyrios Kyrtzidis ID += Entry.getFile().NumCreatedFIDs - 1 /*because of next ++ID*/;
179461ef3db2SArgyrios Kyrtzidis continue;
1795411a254aSKadir Cetinkaya } else if (IncludeLoc.isValid()) {
1796411a254aSKadir Cetinkaya // If file was included but not from FID, there is no more files/macros
1797411a254aSKadir Cetinkaya // that may be "contained" in this file.
1798411a254aSKadir Cetinkaya return;
1799411a254aSKadir Cetinkaya }
1800411a254aSKadir Cetinkaya continue;
180161ef3db2SArgyrios Kyrtzidis }
180261ef3db2SArgyrios Kyrtzidis
1803e841c901SArgyrios Kyrtzidis const ExpansionInfo &ExpInfo = Entry.getExpansion();
1804e841c901SArgyrios Kyrtzidis
1805e841c901SArgyrios Kyrtzidis if (ExpInfo.getExpansionLocStart().isFileID()) {
1806e841c901SArgyrios Kyrtzidis if (!isInFileID(ExpInfo.getExpansionLocStart(), FID))
1807e841c901SArgyrios Kyrtzidis return; // No more files/macros that may be "contained" in this file.
1808e841c901SArgyrios Kyrtzidis }
1809e841c901SArgyrios Kyrtzidis
1810e841c901SArgyrios Kyrtzidis if (!ExpInfo.isMacroArgExpansion())
181161ef3db2SArgyrios Kyrtzidis continue;
181261ef3db2SArgyrios Kyrtzidis
181373ccdb9cSArgyrios Kyrtzidis associateFileChunkWithMacroArgExp(MacroArgsCache, FID,
181473ccdb9cSArgyrios Kyrtzidis ExpInfo.getSpellingLoc(),
181573ccdb9cSArgyrios Kyrtzidis SourceLocation::getMacroLoc(Entry.getOffset()),
181673ccdb9cSArgyrios Kyrtzidis getFileIDSize(FileID::get(ID)));
1817e841c901SArgyrios Kyrtzidis }
181873ccdb9cSArgyrios Kyrtzidis }
181973ccdb9cSArgyrios Kyrtzidis
associateFileChunkWithMacroArgExp(MacroArgsMap & MacroArgsCache,FileID FID,SourceLocation SpellLoc,SourceLocation ExpansionLoc,unsigned ExpansionLength) const182073ccdb9cSArgyrios Kyrtzidis void SourceManager::associateFileChunkWithMacroArgExp(
182173ccdb9cSArgyrios Kyrtzidis MacroArgsMap &MacroArgsCache,
182273ccdb9cSArgyrios Kyrtzidis FileID FID,
182373ccdb9cSArgyrios Kyrtzidis SourceLocation SpellLoc,
182473ccdb9cSArgyrios Kyrtzidis SourceLocation ExpansionLoc,
182573ccdb9cSArgyrios Kyrtzidis unsigned ExpansionLength) const {
182673ccdb9cSArgyrios Kyrtzidis if (!SpellLoc.isFileID()) {
182721401a72SSimon Tatham SourceLocation::UIntTy SpellBeginOffs = SpellLoc.getOffset();
182821401a72SSimon Tatham SourceLocation::UIntTy SpellEndOffs = SpellBeginOffs + ExpansionLength;
182973ccdb9cSArgyrios Kyrtzidis
183073ccdb9cSArgyrios Kyrtzidis // The spelling range for this macro argument expansion can span multiple
183173ccdb9cSArgyrios Kyrtzidis // consecutive FileID entries. Go through each entry contained in the
183273ccdb9cSArgyrios Kyrtzidis // spelling range and if one is itself a macro argument expansion, recurse
183373ccdb9cSArgyrios Kyrtzidis // and associate the file chunk that it represents.
183473ccdb9cSArgyrios Kyrtzidis
183573ccdb9cSArgyrios Kyrtzidis FileID SpellFID; // Current FileID in the spelling range.
183673ccdb9cSArgyrios Kyrtzidis unsigned SpellRelativeOffs;
1837867ea1d4SBenjamin Kramer std::tie(SpellFID, SpellRelativeOffs) = getDecomposedLoc(SpellLoc);
1838918e0ca7SEugene Zelenko while (true) {
183973ccdb9cSArgyrios Kyrtzidis const SLocEntry &Entry = getSLocEntry(SpellFID);
184021401a72SSimon Tatham SourceLocation::UIntTy SpellFIDBeginOffs = Entry.getOffset();
184173ccdb9cSArgyrios Kyrtzidis unsigned SpellFIDSize = getFileIDSize(SpellFID);
184221401a72SSimon Tatham SourceLocation::UIntTy SpellFIDEndOffs = SpellFIDBeginOffs + SpellFIDSize;
184373ccdb9cSArgyrios Kyrtzidis const ExpansionInfo &Info = Entry.getExpansion();
184473ccdb9cSArgyrios Kyrtzidis if (Info.isMacroArgExpansion()) {
184573ccdb9cSArgyrios Kyrtzidis unsigned CurrSpellLength;
184673ccdb9cSArgyrios Kyrtzidis if (SpellFIDEndOffs < SpellEndOffs)
184773ccdb9cSArgyrios Kyrtzidis CurrSpellLength = SpellFIDSize - SpellRelativeOffs;
184873ccdb9cSArgyrios Kyrtzidis else
184973ccdb9cSArgyrios Kyrtzidis CurrSpellLength = ExpansionLength;
185073ccdb9cSArgyrios Kyrtzidis associateFileChunkWithMacroArgExp(MacroArgsCache, FID,
185173ccdb9cSArgyrios Kyrtzidis Info.getSpellingLoc().getLocWithOffset(SpellRelativeOffs),
185273ccdb9cSArgyrios Kyrtzidis ExpansionLoc, CurrSpellLength);
185373ccdb9cSArgyrios Kyrtzidis }
185473ccdb9cSArgyrios Kyrtzidis
185573ccdb9cSArgyrios Kyrtzidis if (SpellFIDEndOffs >= SpellEndOffs)
185673ccdb9cSArgyrios Kyrtzidis return; // we covered all FileID entries in the spelling range.
185773ccdb9cSArgyrios Kyrtzidis
185873ccdb9cSArgyrios Kyrtzidis // Move to the next FileID entry in the spelling range.
185973ccdb9cSArgyrios Kyrtzidis unsigned advance = SpellFIDSize - SpellRelativeOffs + 1;
186073ccdb9cSArgyrios Kyrtzidis ExpansionLoc = ExpansionLoc.getLocWithOffset(advance);
186173ccdb9cSArgyrios Kyrtzidis ExpansionLength -= advance;
186273ccdb9cSArgyrios Kyrtzidis ++SpellFID.ID;
186373ccdb9cSArgyrios Kyrtzidis SpellRelativeOffs = 0;
186473ccdb9cSArgyrios Kyrtzidis }
186573ccdb9cSArgyrios Kyrtzidis }
186673ccdb9cSArgyrios Kyrtzidis
186773ccdb9cSArgyrios Kyrtzidis assert(SpellLoc.isFileID());
1868e841c901SArgyrios Kyrtzidis
186961ef3db2SArgyrios Kyrtzidis unsigned BeginOffs;
187061ef3db2SArgyrios Kyrtzidis if (!isInFileID(SpellLoc, FID, &BeginOffs))
187173ccdb9cSArgyrios Kyrtzidis return;
1872e841c901SArgyrios Kyrtzidis
187373ccdb9cSArgyrios Kyrtzidis unsigned EndOffs = BeginOffs + ExpansionLength;
187461ef3db2SArgyrios Kyrtzidis
187561ef3db2SArgyrios Kyrtzidis // Add a new chunk for this macro argument. A previous macro argument chunk
187661ef3db2SArgyrios Kyrtzidis // may have been lexed again, so e.g. if the map is
187761ef3db2SArgyrios Kyrtzidis // 0 -> SourceLocation()
187861ef3db2SArgyrios Kyrtzidis // 100 -> Expanded loc #1
187961ef3db2SArgyrios Kyrtzidis // 110 -> SourceLocation()
18802a8c18d9SAlexander Kornienko // and we found a new macro FileID that lexed from offset 105 with length 3,
188161ef3db2SArgyrios Kyrtzidis // the new map will be:
188261ef3db2SArgyrios Kyrtzidis // 0 -> SourceLocation()
188361ef3db2SArgyrios Kyrtzidis // 100 -> Expanded loc #1
188461ef3db2SArgyrios Kyrtzidis // 105 -> Expanded loc #2
188561ef3db2SArgyrios Kyrtzidis // 108 -> Expanded loc #1
188661ef3db2SArgyrios Kyrtzidis // 110 -> SourceLocation()
188761ef3db2SArgyrios Kyrtzidis //
188861ef3db2SArgyrios Kyrtzidis // Since re-lexed macro chunks will always be the same size or less of
188961ef3db2SArgyrios Kyrtzidis // previous chunks, we only need to find where the ending of the new macro
189061ef3db2SArgyrios Kyrtzidis // chunk is mapped to and update the map with new begin/end mappings.
189161ef3db2SArgyrios Kyrtzidis
18924bdd6aa1SArgyrios Kyrtzidis MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs);
189361ef3db2SArgyrios Kyrtzidis --I;
189461ef3db2SArgyrios Kyrtzidis SourceLocation EndOffsMappedLoc = I->second;
189573ccdb9cSArgyrios Kyrtzidis MacroArgsCache[BeginOffs] = ExpansionLoc;
189661ef3db2SArgyrios Kyrtzidis MacroArgsCache[EndOffs] = EndOffsMappedLoc;
189761ef3db2SArgyrios Kyrtzidis }
189861ef3db2SArgyrios Kyrtzidis
18999fc8faf9SAdrian Prantl /// If \arg Loc points inside a function macro argument, the returned
190092a47bd9SArgyrios Kyrtzidis /// location will be the macro location in which the argument was expanded.
190192a47bd9SArgyrios Kyrtzidis /// If a macro argument is used multiple times, the expanded location will
190292a47bd9SArgyrios Kyrtzidis /// be at the first expansion of the argument.
190392a47bd9SArgyrios Kyrtzidis /// e.g.
190492a47bd9SArgyrios Kyrtzidis /// MY_MACRO(foo);
190592a47bd9SArgyrios Kyrtzidis /// ^
190692a47bd9SArgyrios Kyrtzidis /// Passing a file location pointing at 'foo', will yield a macro location
190792a47bd9SArgyrios Kyrtzidis /// where 'foo' was expanded into.
19087c06d866SArgyrios Kyrtzidis SourceLocation
getMacroArgExpandedLocation(SourceLocation Loc) const19097c06d866SArgyrios Kyrtzidis SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) const {
191061ef3db2SArgyrios Kyrtzidis if (Loc.isInvalid() || !Loc.isFileID())
191192a47bd9SArgyrios Kyrtzidis return Loc;
191292a47bd9SArgyrios Kyrtzidis
191361ef3db2SArgyrios Kyrtzidis FileID FID;
191461ef3db2SArgyrios Kyrtzidis unsigned Offset;
1915867ea1d4SBenjamin Kramer std::tie(FID, Offset) = getDecomposedLoc(Loc);
191692a47bd9SArgyrios Kyrtzidis if (FID.isInvalid())
191792a47bd9SArgyrios Kyrtzidis return Loc;
191892a47bd9SArgyrios Kyrtzidis
1919d2c6a6d1SVedant Kumar std::unique_ptr<MacroArgsMap> &MacroArgsCache = MacroArgsCacheMap[FID];
1920d2c6a6d1SVedant Kumar if (!MacroArgsCache) {
19212b3d49b6SJonas Devlieghere MacroArgsCache = std::make_unique<MacroArgsMap>();
1922ecc31440SVedant Kumar computeMacroArgsCache(*MacroArgsCache, FID);
1923d2c6a6d1SVedant Kumar }
192492a47bd9SArgyrios Kyrtzidis
19254bdd6aa1SArgyrios Kyrtzidis assert(!MacroArgsCache->empty());
19264bdd6aa1SArgyrios Kyrtzidis MacroArgsMap::iterator I = MacroArgsCache->upper_bound(Offset);
1927ae726fecSJan Korous // In case every element in MacroArgsCache is greater than Offset we can't
1928ae726fecSJan Korous // decrement the iterator.
1929ae726fecSJan Korous if (I == MacroArgsCache->begin())
1930ae726fecSJan Korous return Loc;
1931ae726fecSJan Korous
193261ef3db2SArgyrios Kyrtzidis --I;
193361ef3db2SArgyrios Kyrtzidis
193421401a72SSimon Tatham SourceLocation::UIntTy MacroArgBeginOffs = I->first;
193561ef3db2SArgyrios Kyrtzidis SourceLocation MacroArgExpandedLoc = I->second;
193661ef3db2SArgyrios Kyrtzidis if (MacroArgExpandedLoc.isValid())
1937e6e67deeSArgyrios Kyrtzidis return MacroArgExpandedLoc.getLocWithOffset(Offset - MacroArgBeginOffs);
193861ef3db2SArgyrios Kyrtzidis
193992a47bd9SArgyrios Kyrtzidis return Loc;
194092a47bd9SArgyrios Kyrtzidis }
194192a47bd9SArgyrios Kyrtzidis
194237613a9cSArgyrios Kyrtzidis std::pair<FileID, unsigned>
getDecomposedIncludedLoc(FileID FID) const194337613a9cSArgyrios Kyrtzidis SourceManager::getDecomposedIncludedLoc(FileID FID) const {
19445dca8643SArgyrios Kyrtzidis if (FID.isInvalid())
19455dca8643SArgyrios Kyrtzidis return std::make_pair(FileID(), 0);
19465dca8643SArgyrios Kyrtzidis
194737613a9cSArgyrios Kyrtzidis // Uses IncludedLocMap to retrieve/cache the decomposed loc.
194837613a9cSArgyrios Kyrtzidis
1949918e0ca7SEugene Zelenko using DecompTy = std::pair<FileID, unsigned>;
1950eae2b49fSFangrui Song auto InsertOp = IncludedLocMap.try_emplace(FID);
195137613a9cSArgyrios Kyrtzidis DecompTy &DecompLoc = InsertOp.first->second;
195237613a9cSArgyrios Kyrtzidis if (!InsertOp.second)
195337613a9cSArgyrios Kyrtzidis return DecompLoc; // already in map.
195437613a9cSArgyrios Kyrtzidis
195537613a9cSArgyrios Kyrtzidis SourceLocation UpperLoc;
19565dca8643SArgyrios Kyrtzidis bool Invalid = false;
19575dca8643SArgyrios Kyrtzidis const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
19585dca8643SArgyrios Kyrtzidis if (!Invalid) {
195937613a9cSArgyrios Kyrtzidis if (Entry.isExpansion())
196037613a9cSArgyrios Kyrtzidis UpperLoc = Entry.getExpansion().getExpansionLocStart();
196137613a9cSArgyrios Kyrtzidis else
196237613a9cSArgyrios Kyrtzidis UpperLoc = Entry.getFile().getIncludeLoc();
19635dca8643SArgyrios Kyrtzidis }
196437613a9cSArgyrios Kyrtzidis
196537613a9cSArgyrios Kyrtzidis if (UpperLoc.isValid())
196637613a9cSArgyrios Kyrtzidis DecompLoc = getDecomposedLoc(UpperLoc);
196737613a9cSArgyrios Kyrtzidis
196837613a9cSArgyrios Kyrtzidis return DecompLoc;
196937613a9cSArgyrios Kyrtzidis }
197037613a9cSArgyrios Kyrtzidis
197164ee782eSChandler Carruth /// Given a decomposed source location, move it up the include/expansion stack
197264ee782eSChandler Carruth /// to the parent source location. If this is possible, return the decomposed
197364ee782eSChandler Carruth /// version of the parent in Loc and return false. If Loc is the top-level
197464ee782eSChandler Carruth /// entry, return true and don't modify it.
MoveUpIncludeHierarchy(std::pair<FileID,unsigned> & Loc,const SourceManager & SM)1975a99fa1aeSChris Lattner static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc,
1976a99fa1aeSChris Lattner const SourceManager &SM) {
197737613a9cSArgyrios Kyrtzidis std::pair<FileID, unsigned> UpperLoc = SM.getDecomposedIncludedLoc(Loc.first);
197837613a9cSArgyrios Kyrtzidis if (UpperLoc.first.isInvalid())
1979a99fa1aeSChris Lattner return true; // We reached the top.
1980a99fa1aeSChris Lattner
198137613a9cSArgyrios Kyrtzidis Loc = UpperLoc;
1982a99fa1aeSChris Lattner return false;
1983a99fa1aeSChris Lattner }
1984a99fa1aeSChris Lattner
198508037045STed Kremenek /// Return the cache entry for comparing the given file IDs
198608037045STed Kremenek /// for isBeforeInTranslationUnit.
getInBeforeInTUCache(FileID LFID,FileID RFID) const198708037045STed Kremenek InBeforeInTUCacheEntry &SourceManager::getInBeforeInTUCache(FileID LFID,
198808037045STed Kremenek FileID RFID) const {
198908037045STed Kremenek // This is a magic number for limiting the cache size. It was experimentally
199008037045STed Kremenek // derived from a small Objective-C project (where the cache filled
199108037045STed Kremenek // out to ~250 items). We can make it larger if necessary.
199208037045STed Kremenek enum { MagicCacheSize = 300 };
199308037045STed Kremenek IsBeforeInTUCacheKey Key(LFID, RFID);
199408037045STed Kremenek
199508037045STed Kremenek // If the cache size isn't too large, do a lookup and if necessary default
199608037045STed Kremenek // construct an entry. We can then return it to the caller for direct
199708037045STed Kremenek // use. When they update the value, the cache will get automatically
199808037045STed Kremenek // updated as well.
199908037045STed Kremenek if (IBTUCache.size() < MagicCacheSize)
200008037045STed Kremenek return IBTUCache[Key];
200108037045STed Kremenek
200208037045STed Kremenek // Otherwise, do a lookup that will not construct a new value.
200308037045STed Kremenek InBeforeInTUCache::iterator I = IBTUCache.find(Key);
200408037045STed Kremenek if (I != IBTUCache.end())
200508037045STed Kremenek return I->second;
200608037045STed Kremenek
200708037045STed Kremenek // Fall back to the overflow value.
200808037045STed Kremenek return IBTUCacheOverflow;
200908037045STed Kremenek }
2010a99fa1aeSChris Lattner
20119fc8faf9SAdrian Prantl /// Determines the order of 2 source locations in the translation unit.
201233661d9fSArgyrios Kyrtzidis ///
201333661d9fSArgyrios Kyrtzidis /// \returns true if LHS source location comes before RHS, false otherwise.
isBeforeInTranslationUnit(SourceLocation LHS,SourceLocation RHS) const201433661d9fSArgyrios Kyrtzidis bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
201533661d9fSArgyrios Kyrtzidis SourceLocation RHS) const {
201633661d9fSArgyrios Kyrtzidis assert(LHS.isValid() && RHS.isValid() && "Passed invalid source location!");
201733661d9fSArgyrios Kyrtzidis if (LHS == RHS)
201833661d9fSArgyrios Kyrtzidis return false;
201933661d9fSArgyrios Kyrtzidis
202033661d9fSArgyrios Kyrtzidis std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS);
202133661d9fSArgyrios Kyrtzidis std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS);
202233661d9fSArgyrios Kyrtzidis
20235fd822c2SArgyrios Kyrtzidis // getDecomposedLoc may have failed to return a valid FileID because, e.g. it
20245fd822c2SArgyrios Kyrtzidis // is a serialized one referring to a file that was removed after we loaded
20255fd822c2SArgyrios Kyrtzidis // the PCH.
20265dca8643SArgyrios Kyrtzidis if (LOffs.first.isInvalid() || ROffs.first.isInvalid())
2027d6111d3cSArgyrios Kyrtzidis return LOffs.first.isInvalid() && !ROffs.first.isInvalid();
20285dca8643SArgyrios Kyrtzidis
20297848b388SGabor Horvath std::pair<bool, bool> InSameTU = isInTheSameTranslationUnit(LOffs, ROffs);
20307848b388SGabor Horvath if (InSameTU.first)
20317848b388SGabor Horvath return InSameTU.second;
203233661d9fSArgyrios Kyrtzidis
20331d3b431cSJoerg Sonnenberger // If we arrived here, the location is either in a built-ins buffer or
20341d3b431cSJoerg Sonnenberger // associated with global inline asm. PR5662 and PR22576 are examples.
20351d3b431cSJoerg Sonnenberger
203654c1bcabSDuncan P. N. Exon Smith StringRef LB = getBufferOrFake(LOffs.first).getBufferIdentifier();
203754c1bcabSDuncan P. N. Exon Smith StringRef RB = getBufferOrFake(ROffs.first).getBufferIdentifier();
203899d1b295SMehdi Amini bool LIsBuiltins = LB == "<built-in>";
203999d1b295SMehdi Amini bool RIsBuiltins = RB == "<built-in>";
20401d3b431cSJoerg Sonnenberger // Sort built-in before non-built-in.
20411d3b431cSJoerg Sonnenberger if (LIsBuiltins || RIsBuiltins) {
2042925296b4SDouglas Gregor if (LIsBuiltins != RIsBuiltins)
2043925296b4SDouglas Gregor return LIsBuiltins;
2044925296b4SDouglas Gregor // Both are in built-in buffers, but from different files. We just claim that
2045925296b4SDouglas Gregor // lower IDs come first.
204666d2f924SChris Lattner return LOffs.first < ROffs.first;
204733661d9fSArgyrios Kyrtzidis }
204899d1b295SMehdi Amini bool LIsAsm = LB == "<inline asm>";
204999d1b295SMehdi Amini bool RIsAsm = RB == "<inline asm>";
20501d3b431cSJoerg Sonnenberger // Sort assembler after built-ins, but before the rest.
20511d3b431cSJoerg Sonnenberger if (LIsAsm || RIsAsm) {
20521d3b431cSJoerg Sonnenberger if (LIsAsm != RIsAsm)
20531d3b431cSJoerg Sonnenberger return RIsAsm;
20541d3b431cSJoerg Sonnenberger assert(LOffs.first == ROffs.first);
20551d3b431cSJoerg Sonnenberger return false;
20561d3b431cSJoerg Sonnenberger }
205799d1b295SMehdi Amini bool LIsScratch = LB == "<scratch space>";
205899d1b295SMehdi Amini bool RIsScratch = RB == "<scratch space>";
2059154e57f8SYury Gribov // Sort scratch after inline asm, but before the rest.
2060154e57f8SYury Gribov if (LIsScratch || RIsScratch) {
2061154e57f8SYury Gribov if (LIsScratch != RIsScratch)
2062154e57f8SYury Gribov return LIsScratch;
2063154e57f8SYury Gribov return LOffs.second < ROffs.second;
2064154e57f8SYury Gribov }
20651d3b431cSJoerg Sonnenberger llvm_unreachable("Unsortable locations found");
20661d3b431cSJoerg Sonnenberger }
20674fa23625SChris Lattner
isInTheSameTranslationUnit(std::pair<FileID,unsigned> & LOffs,std::pair<FileID,unsigned> & ROffs) const20687848b388SGabor Horvath std::pair<bool, bool> SourceManager::isInTheSameTranslationUnit(
20697848b388SGabor Horvath std::pair<FileID, unsigned> &LOffs,
20707848b388SGabor Horvath std::pair<FileID, unsigned> &ROffs) const {
20717848b388SGabor Horvath // If the source locations are in the same file, just compare offsets.
20727848b388SGabor Horvath if (LOffs.first == ROffs.first)
20737848b388SGabor Horvath return std::make_pair(true, LOffs.second < ROffs.second);
20747848b388SGabor Horvath
20757848b388SGabor Horvath // If we are comparing a source location with multiple locations in the same
20767848b388SGabor Horvath // file, we get a big win by caching the result.
20777848b388SGabor Horvath InBeforeInTUCacheEntry &IsBeforeInTUCache =
20787848b388SGabor Horvath getInBeforeInTUCache(LOffs.first, ROffs.first);
20797848b388SGabor Horvath
20807848b388SGabor Horvath // If we are comparing a source location with multiple locations in the same
20817848b388SGabor Horvath // file, we get a big win by caching the result.
20827848b388SGabor Horvath if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first))
20837848b388SGabor Horvath return std::make_pair(
20847848b388SGabor Horvath true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second));
20857848b388SGabor Horvath
20867848b388SGabor Horvath // Okay, we missed in the cache, start updating the cache for this query.
20877848b388SGabor Horvath IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first,
20887848b388SGabor Horvath /*isLFIDBeforeRFID=*/LOffs.first.ID < ROffs.first.ID);
20897848b388SGabor Horvath
20907848b388SGabor Horvath // We need to find the common ancestor. The only way of doing this is to
20917848b388SGabor Horvath // build the complete include chain for one and then walking up the chain
20927848b388SGabor Horvath // of the other looking for a match.
20937848b388SGabor Horvath // We use a map from FileID to Offset to store the chain. Easier than writing
20947848b388SGabor Horvath // a custom set hash info that only depends on the first part of a pair.
2095918e0ca7SEugene Zelenko using LocSet = llvm::SmallDenseMap<FileID, unsigned, 16>;
20967848b388SGabor Horvath LocSet LChain;
20977848b388SGabor Horvath do {
20987848b388SGabor Horvath LChain.insert(LOffs);
20997848b388SGabor Horvath // We catch the case where LOffs is in a file included by ROffs and
21007848b388SGabor Horvath // quit early. The other way round unfortunately remains suboptimal.
21017848b388SGabor Horvath } while (LOffs.first != ROffs.first && !MoveUpIncludeHierarchy(LOffs, *this));
21027848b388SGabor Horvath LocSet::iterator I;
21037848b388SGabor Horvath while((I = LChain.find(ROffs.first)) == LChain.end()) {
21047848b388SGabor Horvath if (MoveUpIncludeHierarchy(ROffs, *this))
21057848b388SGabor Horvath break; // Met at topmost file.
21067848b388SGabor Horvath }
21077848b388SGabor Horvath if (I != LChain.end())
21087848b388SGabor Horvath LOffs = *I;
21097848b388SGabor Horvath
21107848b388SGabor Horvath // If we exited because we found a nearest common ancestor, compare the
21117848b388SGabor Horvath // locations within the common file and cache them.
21127848b388SGabor Horvath if (LOffs.first == ROffs.first) {
21137848b388SGabor Horvath IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second);
21147848b388SGabor Horvath return std::make_pair(
21157848b388SGabor Horvath true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second));
21167848b388SGabor Horvath }
21177848b388SGabor Horvath // Clear the lookup cache, it depends on a common location.
21187848b388SGabor Horvath IsBeforeInTUCache.clear();
21197848b388SGabor Horvath return std::make_pair(false, false);
21207848b388SGabor Horvath }
21217848b388SGabor Horvath
PrintStats() const21227a51313dSChris Lattner void SourceManager::PrintStats() const {
212389b422c1SBenjamin Kramer llvm::errs() << "\n*** Source Manager Stats:\n";
212489b422c1SBenjamin Kramer llvm::errs() << FileInfos.size() << " files mapped, " << MemBufferInfos.size()
21256d61c3e6SChris Lattner << " mem buffers mapped.\n";
2126925296b4SDouglas Gregor llvm::errs() << LocalSLocEntryTable.size() << " local SLocEntry's allocated ("
212743e0c4a8STed Kremenek << llvm::capacity_in_bytes(LocalSLocEntryTable)
21282cc62093SArgyrios Kyrtzidis << " bytes of capacity), "
2129925296b4SDouglas Gregor << NextLocalOffset << "B of Sloc address space used.\n";
2130925296b4SDouglas Gregor llvm::errs() << LoadedSLocEntryTable.size()
2131925296b4SDouglas Gregor << " loaded SLocEntries allocated, "
213292a47bd9SArgyrios Kyrtzidis << MaxLoadedOffset - CurrentLoadedOffset
2133925296b4SDouglas Gregor << "B of Sloc address space used.\n";
21347a51313dSChris Lattner
21357a51313dSChris Lattner unsigned NumLineNumsComputed = 0;
21367a51313dSChris Lattner unsigned NumFileBytesMapped = 0;
2137c8233df6SChris Lattner for (fileinfo_iterator I = fileinfo_begin(), E = fileinfo_end(); I != E; ++I){
2138dbbc4f4eSDuncan P. N. Exon Smith NumLineNumsComputed += bool(I->second->SourceLineCache);
2139c8233df6SChris Lattner NumFileBytesMapped += I->second->getSizeBytesMapped();
21407a51313dSChris Lattner }
21414bdd6aa1SArgyrios Kyrtzidis unsigned NumMacroArgsComputed = MacroArgsCacheMap.size();
21427a51313dSChris Lattner
214389b422c1SBenjamin Kramer llvm::errs() << NumFileBytesMapped << " bytes of files mapped, "
214461ef3db2SArgyrios Kyrtzidis << NumLineNumsComputed << " files with line #'s computed, "
214561ef3db2SArgyrios Kyrtzidis << NumMacroArgsComputed << " files with macro args computed.\n";
214689b422c1SBenjamin Kramer llvm::errs() << "FileID scans: " << NumLinearScans << " linear, "
21474fa23625SChris Lattner << NumBinaryProbes << " binary.\n";
21487a51313dSChris Lattner }
2149258ae54aSDouglas Gregor
dump() const215003a06dd1SRichard Smith LLVM_DUMP_METHOD void SourceManager::dump() const {
215103a06dd1SRichard Smith llvm::raw_ostream &out = llvm::errs();
215203a06dd1SRichard Smith
215303a06dd1SRichard Smith auto DumpSLocEntry = [&](int ID, const SrcMgr::SLocEntry &Entry,
215421401a72SSimon Tatham llvm::Optional<SourceLocation::UIntTy> NextStart) {
215503a06dd1SRichard Smith out << "SLocEntry <FileID " << ID << "> " << (Entry.isFile() ? "file" : "expansion")
215603a06dd1SRichard Smith << " <SourceLocation " << Entry.getOffset() << ":";
215703a06dd1SRichard Smith if (NextStart)
215803a06dd1SRichard Smith out << *NextStart << ">\n";
215903a06dd1SRichard Smith else
216003a06dd1SRichard Smith out << "???\?>\n";
216103a06dd1SRichard Smith if (Entry.isFile()) {
216203a06dd1SRichard Smith auto &FI = Entry.getFile();
216303a06dd1SRichard Smith if (FI.NumCreatedFIDs)
216403a06dd1SRichard Smith out << " covers <FileID " << ID << ":" << int(ID + FI.NumCreatedFIDs)
216503a06dd1SRichard Smith << ">\n";
216603a06dd1SRichard Smith if (FI.getIncludeLoc().isValid())
216703a06dd1SRichard Smith out << " included from " << FI.getIncludeLoc().getOffset() << "\n";
216874a87834SDuncan P. N. Exon Smith auto &CC = FI.getContentCache();
216974a87834SDuncan P. N. Exon Smith out << " for " << (CC.OrigEntry ? CC.OrigEntry->getName() : "<none>")
217003a06dd1SRichard Smith << "\n";
217174a87834SDuncan P. N. Exon Smith if (CC.BufferOverridden)
217203a06dd1SRichard Smith out << " contents overridden\n";
217374a87834SDuncan P. N. Exon Smith if (CC.ContentsEntry != CC.OrigEntry) {
217403a06dd1SRichard Smith out << " contents from "
217574a87834SDuncan P. N. Exon Smith << (CC.ContentsEntry ? CC.ContentsEntry->getName() : "<none>")
217603a06dd1SRichard Smith << "\n";
217703a06dd1SRichard Smith }
217803a06dd1SRichard Smith } else {
217903a06dd1SRichard Smith auto &EI = Entry.getExpansion();
218003a06dd1SRichard Smith out << " spelling from " << EI.getSpellingLoc().getOffset() << "\n";
218103a06dd1SRichard Smith out << " macro " << (EI.isMacroArgExpansion() ? "arg" : "body")
218203a06dd1SRichard Smith << " range <" << EI.getExpansionLocStart().getOffset() << ":"
218303a06dd1SRichard Smith << EI.getExpansionLocEnd().getOffset() << ">\n";
218403a06dd1SRichard Smith }
218503a06dd1SRichard Smith };
218603a06dd1SRichard Smith
218703a06dd1SRichard Smith // Dump local SLocEntries.
218803a06dd1SRichard Smith for (unsigned ID = 0, NumIDs = LocalSLocEntryTable.size(); ID != NumIDs; ++ID) {
218903a06dd1SRichard Smith DumpSLocEntry(ID, LocalSLocEntryTable[ID],
219003a06dd1SRichard Smith ID == NumIDs - 1 ? NextLocalOffset
219103a06dd1SRichard Smith : LocalSLocEntryTable[ID + 1].getOffset());
219203a06dd1SRichard Smith }
219303a06dd1SRichard Smith // Dump loaded SLocEntries.
219421401a72SSimon Tatham llvm::Optional<SourceLocation::UIntTy> NextStart;
219503a06dd1SRichard Smith for (unsigned Index = 0; Index != LoadedSLocEntryTable.size(); ++Index) {
219603a06dd1SRichard Smith int ID = -(int)Index - 2;
219703a06dd1SRichard Smith if (SLocEntryLoaded[Index]) {
219803a06dd1SRichard Smith DumpSLocEntry(ID, LoadedSLocEntryTable[Index], NextStart);
219903a06dd1SRichard Smith NextStart = LoadedSLocEntryTable[Index].getOffset();
220003a06dd1SRichard Smith } else {
220103a06dd1SRichard Smith NextStart = None;
220203a06dd1SRichard Smith }
220303a06dd1SRichard Smith }
220403a06dd1SRichard Smith }
220503a06dd1SRichard Smith
2206918e0ca7SEugene Zelenko ExternalSLocEntrySource::~ExternalSLocEntrySource() = default;
22078d587900STed Kremenek
22088d587900STed Kremenek /// Return the amount of memory used by memory buffers, breaking down
22098d587900STed Kremenek /// by heap-backed versus mmap'ed memory.
getMemoryBufferSizes() const22108d587900STed Kremenek SourceManager::MemoryBufferSizes SourceManager::getMemoryBufferSizes() const {
22118d587900STed Kremenek size_t malloc_bytes = 0;
22128d587900STed Kremenek size_t mmap_bytes = 0;
22138d587900STed Kremenek
22148d587900STed Kremenek for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i)
22158d587900STed Kremenek if (size_t sized_mapped = MemBufferInfos[i]->getSizeBytesMapped())
22168d587900STed Kremenek switch (MemBufferInfos[i]->getMemoryBufferKind()) {
22178d587900STed Kremenek case llvm::MemoryBuffer::MemoryBuffer_MMap:
22188d587900STed Kremenek mmap_bytes += sized_mapped;
22198d587900STed Kremenek break;
22208d587900STed Kremenek case llvm::MemoryBuffer::MemoryBuffer_Malloc:
22218d587900STed Kremenek malloc_bytes += sized_mapped;
22228d587900STed Kremenek break;
22238d587900STed Kremenek }
22248d587900STed Kremenek
22258d587900STed Kremenek return MemoryBufferSizes(malloc_bytes, mmap_bytes);
22268d587900STed Kremenek }
22278d587900STed Kremenek
getDataStructureSizes() const2228120992adSTed Kremenek size_t SourceManager::getDataStructureSizes() const {
22296eec06d0SArgyrios Kyrtzidis size_t size = llvm::capacity_in_bytes(MemBufferInfos)
223043e0c4a8STed Kremenek + llvm::capacity_in_bytes(LocalSLocEntryTable)
223143e0c4a8STed Kremenek + llvm::capacity_in_bytes(LoadedSLocEntryTable)
223243e0c4a8STed Kremenek + llvm::capacity_in_bytes(SLocEntryLoaded)
22336eec06d0SArgyrios Kyrtzidis + llvm::capacity_in_bytes(FileInfos);
22346eec06d0SArgyrios Kyrtzidis
22356eec06d0SArgyrios Kyrtzidis if (OverriddenFilesInfo)
22366eec06d0SArgyrios Kyrtzidis size += llvm::capacity_in_bytes(OverriddenFilesInfo->OverriddenFiles);
22376eec06d0SArgyrios Kyrtzidis
22386eec06d0SArgyrios Kyrtzidis return size;
2239120992adSTed Kremenek }
22402e538089SEric Liu
SourceManagerForFile(StringRef FileName,StringRef Content)22412e538089SEric Liu SourceManagerForFile::SourceManagerForFile(StringRef FileName,
22422e538089SEric Liu StringRef Content) {
22432e538089SEric Liu // This is referenced by `FileMgr` and will be released by `FileMgr` when it
22442e538089SEric Liu // is deleted.
2245fc51490bSJonas Devlieghere IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
2246fc51490bSJonas Devlieghere new llvm::vfs::InMemoryFileSystem);
22472e538089SEric Liu InMemoryFileSystem->addFile(
22482e538089SEric Liu FileName, 0,
22492e538089SEric Liu llvm::MemoryBuffer::getMemBuffer(Content, FileName,
22502e538089SEric Liu /*RequiresNullTerminator=*/false));
22512e538089SEric Liu // This is passed to `SM` as reference, so the pointer has to be referenced
22522e538089SEric Liu // in `Environment` so that `FileMgr` can out-live this function scope.
22532e538089SEric Liu FileMgr =
22542b3d49b6SJonas Devlieghere std::make_unique<FileManager>(FileSystemOptions(), InMemoryFileSystem);
22552e538089SEric Liu // This is passed to `SM` as reference, so the pointer has to be referenced
22562e538089SEric Liu // by `Environment` due to the same reason above.
22572b3d49b6SJonas Devlieghere Diagnostics = std::make_unique<DiagnosticsEngine>(
22582e538089SEric Liu IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
22592e538089SEric Liu new DiagnosticOptions);
22602b3d49b6SJonas Devlieghere SourceMgr = std::make_unique<SourceManager>(*Diagnostics, *FileMgr);
22618d323d15SHarlan Haskins FileID ID = SourceMgr->createFileID(*FileMgr->getFile(FileName),
22622e538089SEric Liu SourceLocation(), clang::SrcMgr::C_User);
22632e538089SEric Liu assert(ID.isValid());
22642e538089SEric Liu SourceMgr->setMainFileID(ID);
22652e538089SEric Liu }
2266