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" 29918e0ca7SEugene Zelenko #include "llvm/Support/ErrorHandling.h" 30918e0ca7SEugene Zelenko #include "llvm/Support/FileSystem.h" 31918e0ca7SEugene Zelenko #include "llvm/Support/MathExtras.h" 327a51313dSChris Lattner #include "llvm/Support/MemoryBuffer.h" 338aaf4995SMichael J. Spencer #include "llvm/Support/Path.h" 343a02247dSChandler Carruth #include "llvm/Support/raw_ostream.h" 357a51313dSChris Lattner #include <algorithm> 36918e0ca7SEugene Zelenko #include <cassert> 37918e0ca7SEugene Zelenko #include <cstddef> 38918e0ca7SEugene Zelenko #include <cstdint> 39918e0ca7SEugene Zelenko #include <memory> 40918e0ca7SEugene Zelenko #include <tuple> 41918e0ca7SEugene Zelenko #include <utility> 42918e0ca7SEugene Zelenko #include <vector> 43802b7760SDouglas Gregor 447a51313dSChris Lattner using namespace clang; 457a51313dSChris Lattner using namespace SrcMgr; 467a51313dSChris Lattner using llvm::MemoryBuffer; 477a51313dSChris Lattner 48153a0f1fSChris Lattner //===----------------------------------------------------------------------===// 494fa23625SChris Lattner // SourceManager Helper Classes 50153a0f1fSChris Lattner //===----------------------------------------------------------------------===// 514fa23625SChris Lattner 5264ee782eSChandler Carruth /// getSizeBytesMapped - Returns the number of bytes actually mapped for this 5364ee782eSChandler Carruth /// ContentCache. This can be 0 if the MemBuffer was not actually expanded. 5412c2af44STed Kremenek unsigned ContentCache::getSizeBytesMapped() const { 5529631451SDuncan P. N. Exon Smith return Buffer ? Buffer->getBufferSize() : 0; 5612c2af44STed Kremenek } 5712c2af44STed Kremenek 588d587900STed Kremenek /// Returns the kind of memory used to back the memory buffer for 598d587900STed Kremenek /// this content cache. This is used for performance analysis. 608d587900STed Kremenek llvm::MemoryBuffer::BufferKind ContentCache::getMemoryBufferKind() const { 6129631451SDuncan P. N. Exon Smith assert(Buffer); 628d587900STed Kremenek 638d587900STed Kremenek // Should be unreachable, but keep for sanity. 6429631451SDuncan P. N. Exon Smith if (!Buffer) 658d587900STed Kremenek return llvm::MemoryBuffer::MemoryBuffer_Malloc; 668d587900STed Kremenek 6729631451SDuncan P. N. Exon Smith return Buffer->getBufferKind(); 688d587900STed Kremenek } 698d587900STed Kremenek 7012c2af44STed Kremenek /// getSize - Returns the size of the content encapsulated by this ContentCache. 7112c2af44STed Kremenek /// This can be the size of the source file or the size of an arbitrary 7212c2af44STed Kremenek /// scratch buffer. If the ContentCache encapsulates a source file, that 7353ad6b94SDouglas Gregor /// file is not lazily brought in from disk to satisfy this query. 7412c2af44STed Kremenek unsigned ContentCache::getSize() const { 7529631451SDuncan P. N. Exon Smith return Buffer ? (unsigned)Buffer->getBufferSize() 7611e6f0a6SArgyrios Kyrtzidis : (unsigned)ContentsEntry->getSize(); 7712c2af44STed Kremenek } 7812c2af44STed Kremenek 798fa5e98fSpaulhoad const char *ContentCache::getInvalidBOM(StringRef BufStr) { 808fa5e98fSpaulhoad // If the buffer is valid, check to see if it has a UTF Byte Order Mark 818fa5e98fSpaulhoad // (BOM). We only support UTF-8 with and without a BOM right now. See 828fa5e98fSpaulhoad // http://en.wikipedia.org/wiki/Byte_order_mark for more information. 838fa5e98fSpaulhoad const char *InvalidBOM = 848fa5e98fSpaulhoad llvm::StringSwitch<const char *>(BufStr) 858fa5e98fSpaulhoad .StartsWith(llvm::StringLiteral::withInnerNUL("\x00\x00\xFE\xFF"), 868fa5e98fSpaulhoad "UTF-32 (BE)") 878fa5e98fSpaulhoad .StartsWith(llvm::StringLiteral::withInnerNUL("\xFF\xFE\x00\x00"), 888fa5e98fSpaulhoad "UTF-32 (LE)") 898fa5e98fSpaulhoad .StartsWith("\xFE\xFF", "UTF-16 (BE)") 908fa5e98fSpaulhoad .StartsWith("\xFF\xFE", "UTF-16 (LE)") 918fa5e98fSpaulhoad .StartsWith("\x2B\x2F\x76", "UTF-7") 928fa5e98fSpaulhoad .StartsWith("\xF7\x64\x4C", "UTF-1") 938fa5e98fSpaulhoad .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC") 948fa5e98fSpaulhoad .StartsWith("\x0E\xFE\xFF", "SCSU") 958fa5e98fSpaulhoad .StartsWith("\xFB\xEE\x28", "BOCU-1") 968fa5e98fSpaulhoad .StartsWith("\x84\x31\x95\x33", "GB-18030") 978fa5e98fSpaulhoad .Default(nullptr); 988fa5e98fSpaulhoad 998fa5e98fSpaulhoad return InvalidBOM; 1008fa5e98fSpaulhoad } 1018fa5e98fSpaulhoad 102d758f79eSDuncan P. N. Exon Smith llvm::Optional<llvm::MemoryBufferRef> 103d758f79eSDuncan P. N. Exon Smith ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM, 104d758f79eSDuncan P. N. Exon Smith SourceLocation Loc) const { 1055631b052SChris Lattner // Lazily create the Buffer for ContentCaches that wrap files. If we already 10657540c5bSChris Lattner // computed it, just return what we have. 1071d78e210SDuncan P. N. Exon Smith if (IsBufferInvalid) 108747b134dSDuncan P. N. Exon Smith return None; 10929631451SDuncan P. N. Exon Smith if (Buffer) 11029631451SDuncan P. N. Exon Smith return Buffer->getMemBufferRef(); 111d758f79eSDuncan P. N. Exon Smith if (!ContentsEntry) 112747b134dSDuncan P. N. Exon Smith return None; 1135631b052SChris Lattner 1144aa97e3dSDuncan P. N. Exon Smith // Start with the assumption that the buffer is invalid to simplify early 1154aa97e3dSDuncan P. N. Exon Smith // return paths. 1164aa97e3dSDuncan P. N. Exon Smith IsBufferInvalid = true; 1174aa97e3dSDuncan P. N. Exon Smith 118979ae80aSRichard Smith // Check that the file's size fits in an 'unsigned' (with room for a 119979ae80aSRichard Smith // past-the-end value). This is deeply regrettable, but various parts of 120979ae80aSRichard Smith // Clang (including elsewhere in this file!) use 'unsigned' to represent file 121979ae80aSRichard Smith // offsets, line numbers, string literal lengths, and so on, and fail 122979ae80aSRichard Smith // miserably on large source files. 123a372bb21SSimon Pilgrim if ((uint64_t)ContentsEntry->getSize() >= 124a372bb21SSimon Pilgrim std::numeric_limits<unsigned>::max()) { 125979ae80aSRichard Smith if (Diag.isDiagnosticInFlight()) 126979ae80aSRichard Smith Diag.SetDelayedDiagnostic(diag::err_file_too_large, 127979ae80aSRichard Smith ContentsEntry->getName()); 128979ae80aSRichard Smith else 129979ae80aSRichard Smith Diag.Report(Loc, diag::err_file_too_large) 130979ae80aSRichard Smith << ContentsEntry->getName(); 131979ae80aSRichard Smith 132747b134dSDuncan P. N. Exon Smith return None; 133979ae80aSRichard Smith } 134979ae80aSRichard Smith 135f5848190SDuncan P. N. Exon Smith auto BufferOrError = FM.getBufferForFile(ContentsEntry, IsFileVolatile); 1367cea5f17SDaniel Dunbar 1377cea5f17SDaniel Dunbar // If we were unable to open the file, then we are in an inconsistent 1387cea5f17SDaniel Dunbar // situation where the content cache referenced a file which no longer 1397cea5f17SDaniel Dunbar // exists. Most likely, we were using a stat cache with an invalid entry but 1407cea5f17SDaniel Dunbar // the file could also have been removed during processing. Since we can't 1417cea5f17SDaniel Dunbar // really deal with this situation, just create an empty buffer. 142a885796dSBenjamin Kramer if (!BufferOrError) { 14385795316SDouglas Gregor if (Diag.isDiagnosticInFlight()) 14485795316SDouglas Gregor Diag.SetDelayedDiagnostic(diag::err_cannot_open_file, 145a885796dSBenjamin Kramer ContentsEntry->getName(), 146a885796dSBenjamin Kramer BufferOrError.getError().message()); 14785795316SDouglas Gregor else 148d0040648SArgyrios Kyrtzidis Diag.Report(Loc, diag::err_cannot_open_file) 149a885796dSBenjamin Kramer << ContentsEntry->getName() << BufferOrError.getError().message(); 15085795316SDouglas Gregor 151747b134dSDuncan P. N. Exon Smith return None; 1525631b052SChris Lattner } 1535631b052SChris Lattner 15429631451SDuncan P. N. Exon Smith Buffer = std::move(*BufferOrError); 155a885796dSBenjamin Kramer 1564ac569b2SChris Lattner // Check that the file's size is the same as in the file entry (which may 1574ac569b2SChris Lattner // have come from a stat cache). 158156e8b37SDuncan P. N. Exon Smith if (Buffer->getBufferSize() != (size_t)ContentsEntry->getSize()) { 15985795316SDouglas Gregor if (Diag.isDiagnosticInFlight()) 16085795316SDouglas Gregor Diag.SetDelayedDiagnostic(diag::err_file_modified, 16111e6f0a6SArgyrios Kyrtzidis ContentsEntry->getName()); 16285795316SDouglas Gregor else 163d0040648SArgyrios Kyrtzidis Diag.Report(Loc, diag::err_file_modified) 16411e6f0a6SArgyrios Kyrtzidis << ContentsEntry->getName(); 16585795316SDouglas Gregor 166747b134dSDuncan P. N. Exon Smith return None; 1677cea5f17SDaniel Dunbar } 1688fbe98b3SChris Lattner 1698fbe98b3SChris Lattner // If the buffer is valid, check to see if it has a UTF Byte Order Mark 1707f36a79eSEric Christopher // (BOM). We only support UTF-8 with and without a BOM right now. See 1718fbe98b3SChris Lattner // http://en.wikipedia.org/wiki/Byte_order_mark for more information. 17229631451SDuncan P. N. Exon Smith StringRef BufStr = Buffer->getBuffer(); 1738fa5e98fSpaulhoad const char *InvalidBOM = getInvalidBOM(BufStr); 1748fbe98b3SChris Lattner 1757f36a79eSEric Christopher if (InvalidBOM) { 176d0040648SArgyrios Kyrtzidis Diag.Report(Loc, diag::err_unsupported_bom) 1777f36a79eSEric Christopher << InvalidBOM << ContentsEntry->getName(); 178747b134dSDuncan P. N. Exon Smith return None; 179763ea559STed Kremenek } 180802b7760SDouglas Gregor 1814aa97e3dSDuncan P. N. Exon Smith // Buffer has been validated. 1824aa97e3dSDuncan P. N. Exon Smith IsBufferInvalid = false; 18329631451SDuncan P. N. Exon Smith return Buffer->getMemBufferRef(); 18412c2af44STed Kremenek } 18512c2af44STed Kremenek 1860e62c1ccSChris Lattner unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) { 187eae2b49fSFangrui Song auto IterBool = FilenameIDs.try_emplace(Name, FilenamesByID.size()); 18813156b68SDavid Blaikie if (IterBool.second) 18913156b68SDavid Blaikie FilenamesByID.push_back(&*IterBool.first); 19013156b68SDavid Blaikie return IterBool.first->second; 191b5fba6f8SChris Lattner } 192b5fba6f8SChris Lattner 193eb00ee07SReid Kleckner /// Add a line note to the line table that indicates that there is a \#line or 194eb00ee07SReid Kleckner /// GNU line marker at the specified FID/Offset location which changes the 195eb00ee07SReid Kleckner /// presumed location to LineNo/FilenameID. If EntryExit is 0, then this doesn't 196eb00ee07SReid Kleckner /// change the presumed \#include stack. If it is 1, this is a file entry, if 197eb00ee07SReid Kleckner /// it is 2 then this is a file exit. FileKind specifies whether this is a 198eb00ee07SReid Kleckner /// system header or extern C system header. 199eb00ee07SReid Kleckner void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, unsigned LineNo, 200eb00ee07SReid Kleckner int FilenameID, unsigned EntryExit, 2010a1a8d85SChris Lattner SrcMgr::CharacteristicKind FileKind) { 2020a1a8d85SChris Lattner std::vector<LineEntry> &Entries = LineEntries[FID]; 2030a1a8d85SChris Lattner 204eb00ee07SReid Kleckner // An unspecified FilenameID means use the last filename if available, or the 205eb00ee07SReid Kleckner // main source file otherwise. 206eb00ee07SReid Kleckner if (FilenameID == -1 && !Entries.empty()) 207eb00ee07SReid Kleckner FilenameID = Entries.back().FilenameID; 208eb00ee07SReid Kleckner 2090a1a8d85SChris Lattner assert((Entries.empty() || Entries.back().FileOffset < Offset) && 2100a1a8d85SChris Lattner "Adding line entries out of order!"); 2110a1a8d85SChris Lattner 2121c967784SChris Lattner unsigned IncludeOffset = 0; 2131c967784SChris Lattner if (EntryExit == 0) { // No #include stack change. 2141c967784SChris Lattner IncludeOffset = Entries.empty() ? 0 : Entries.back().IncludeOffset; 2151c967784SChris Lattner } else if (EntryExit == 1) { 2161c967784SChris Lattner IncludeOffset = Offset-1; 2171c967784SChris Lattner } else if (EntryExit == 2) { 2181c967784SChris Lattner assert(!Entries.empty() && Entries.back().IncludeOffset && 2191c967784SChris Lattner "PPDirectives should have caught case when popping empty include stack"); 2200a1a8d85SChris Lattner 2211c967784SChris Lattner // Get the include loc of the last entries' include loc as our include loc. 2221c967784SChris Lattner IncludeOffset = 0; 2231c967784SChris Lattner if (const LineEntry *PrevEntry = 2241c967784SChris Lattner FindNearestLineEntry(FID, Entries.back().IncludeOffset)) 2251c967784SChris Lattner IncludeOffset = PrevEntry->IncludeOffset; 2261c967784SChris Lattner } 2270a1a8d85SChris Lattner 2281c967784SChris Lattner Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, FileKind, 2291c967784SChris Lattner IncludeOffset)); 2300a1a8d85SChris Lattner } 2310a1a8d85SChris Lattner 232d4293922SChris Lattner /// FindNearestLineEntry - Find the line entry nearest to FID that is before 233d4293922SChris Lattner /// it. If there is no line entry before Offset in FID, return null. 23402c2dbf4SDouglas Gregor const LineEntry *LineTableInfo::FindNearestLineEntry(FileID FID, 235d4293922SChris Lattner unsigned Offset) { 236d4293922SChris Lattner const std::vector<LineEntry> &Entries = LineEntries[FID]; 237d4293922SChris Lattner assert(!Entries.empty() && "No #line entries for this FID after all!"); 238d4293922SChris Lattner 239334a2adaSChris Lattner // It is very common for the query to be after the last #line, check this 240334a2adaSChris Lattner // first. 241334a2adaSChris Lattner if (Entries.back().FileOffset <= Offset) 242334a2adaSChris Lattner return &Entries.back(); 243d4293922SChris Lattner 244334a2adaSChris Lattner // Do a binary search to find the maximal element that is still before Offset. 2457264a474SFangrui Song std::vector<LineEntry>::const_iterator I = llvm::upper_bound(Entries, Offset); 2467264a474SFangrui Song if (I == Entries.begin()) 2477264a474SFangrui Song return nullptr; 248334a2adaSChris Lattner return &*--I; 249d4293922SChris Lattner } 2506e0e1f49SChris Lattner 2519fc8faf9SAdrian Prantl /// Add a new line entry that has already been encoded into 2524c7626e7SDouglas Gregor /// the internal representation of the line table. 25302c2dbf4SDouglas Gregor void LineTableInfo::AddEntry(FileID FID, 2544c7626e7SDouglas Gregor const std::vector<LineEntry> &Entries) { 2554c7626e7SDouglas Gregor LineEntries[FID] = Entries; 2564c7626e7SDouglas Gregor } 2576e0e1f49SChris Lattner 258b5fba6f8SChris Lattner /// getLineTableFilenameID - Return the uniqued ID for the specified filename. 2590e62c1ccSChris Lattner unsigned SourceManager::getLineTableFilenameID(StringRef Name) { 2605eeeab7dSVedant Kumar return getLineTable().getLineTableFilenameID(Name); 261b5fba6f8SChris Lattner } 262b5fba6f8SChris Lattner 2631eaa70a6SChris Lattner /// AddLineNote - Add a line note to the line table for the FileID and offset 2641eaa70a6SChris Lattner /// specified by Loc. If FilenameID is -1, it is considered to be 2651eaa70a6SChris Lattner /// unspecified. 2661eaa70a6SChris Lattner void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, 2670a1a8d85SChris Lattner int FilenameID, bool IsFileEntry, 268eb00ee07SReid Kleckner bool IsFileExit, 269eb00ee07SReid Kleckner SrcMgr::CharacteristicKind FileKind) { 270c7ca5218SChandler Carruth std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); 27149f754f4SDouglas Gregor 27249f754f4SDouglas Gregor bool Invalid = false; 27349f754f4SDouglas Gregor const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); 27449f754f4SDouglas Gregor if (!Entry.isFile() || Invalid) 27549f754f4SDouglas Gregor return; 27649f754f4SDouglas Gregor 27749f754f4SDouglas Gregor const SrcMgr::FileInfo &FileInfo = Entry.getFile(); 2780a1a8d85SChris Lattner 2790a1a8d85SChris Lattner // Remember that this file has #line directives now if it doesn't already. 2800a1a8d85SChris Lattner const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives(); 2810a1a8d85SChris Lattner 2825eeeab7dSVedant Kumar (void) getLineTable(); 2830a1a8d85SChris Lattner 2840a1a8d85SChris Lattner unsigned EntryExit = 0; 2850a1a8d85SChris Lattner if (IsFileEntry) 2860a1a8d85SChris Lattner EntryExit = 1; 2870a1a8d85SChris Lattner else if (IsFileExit) 2880a1a8d85SChris Lattner EntryExit = 2; 2890a1a8d85SChris Lattner 29002c2dbf4SDouglas Gregor LineTable->AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID, 2910a1a8d85SChris Lattner EntryExit, FileKind); 2920a1a8d85SChris Lattner } 2930a1a8d85SChris Lattner 2944c7626e7SDouglas Gregor LineTableInfo &SourceManager::getLineTable() { 295f1186c5aSCraig Topper if (!LineTable) 296a2dcbd36SNico Weber LineTable.reset(new LineTableInfo()); 2974c7626e7SDouglas Gregor return *LineTable; 2984c7626e7SDouglas Gregor } 2991eaa70a6SChris Lattner 300153a0f1fSChris Lattner //===----------------------------------------------------------------------===// 3014fa23625SChris Lattner // Private 'Create' methods. 302153a0f1fSChris Lattner //===----------------------------------------------------------------------===// 30312c2af44STed Kremenek 3046d7833f1SArgyrios Kyrtzidis SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr, 3056d7833f1SArgyrios Kyrtzidis bool UserFilesAreVolatile) 306918e0ca7SEugene Zelenko : Diag(Diag), FileMgr(FileMgr), UserFilesAreVolatile(UserFilesAreVolatile) { 307d0040648SArgyrios Kyrtzidis clearIDTables(); 308d0040648SArgyrios Kyrtzidis Diag.setSourceManager(this); 309d0040648SArgyrios Kyrtzidis } 310d0040648SArgyrios Kyrtzidis 311b5fba6f8SChris Lattner SourceManager::~SourceManager() { 312c8233df6SChris Lattner // Delete FileEntry objects corresponding to content caches. Since the actual 313c8233df6SChris Lattner // content cache objects are bump pointer allocated, we just have to run the 314c8233df6SChris Lattner // dtors, but we call the deallocate method for completeness. 315c8233df6SChris Lattner for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i) { 316af41b3f0SArgyrios Kyrtzidis if (MemBufferInfos[i]) { 317c8233df6SChris Lattner MemBufferInfos[i]->~ContentCache(); 318c8233df6SChris Lattner ContentCacheAlloc.Deallocate(MemBufferInfos[i]); 319c8233df6SChris Lattner } 320af41b3f0SArgyrios Kyrtzidis } 321c8233df6SChris Lattner for (llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::iterator 322c8233df6SChris Lattner I = FileInfos.begin(), E = FileInfos.end(); I != E; ++I) { 323af41b3f0SArgyrios Kyrtzidis if (I->second) { 324c8233df6SChris Lattner I->second->~ContentCache(); 325c8233df6SChris Lattner ContentCacheAlloc.Deallocate(I->second); 326c8233df6SChris Lattner } 327af41b3f0SArgyrios Kyrtzidis } 328b5fba6f8SChris Lattner } 329b5fba6f8SChris Lattner 330b5fba6f8SChris Lattner void SourceManager::clearIDTables() { 331b5fba6f8SChris Lattner MainFileID = FileID(); 332925296b4SDouglas Gregor LocalSLocEntryTable.clear(); 333925296b4SDouglas Gregor LoadedSLocEntryTable.clear(); 334925296b4SDouglas Gregor SLocEntryLoaded.clear(); 335b5fba6f8SChris Lattner LastLineNoFileIDQuery = FileID(); 336f1186c5aSCraig Topper LastLineNoContentCache = nullptr; 337b5fba6f8SChris Lattner LastFileIDLookup = FileID(); 338b5fba6f8SChris Lattner 339b5fba6f8SChris Lattner if (LineTable) 340b5fba6f8SChris Lattner LineTable->clear(); 341b5fba6f8SChris Lattner 34264ee782eSChandler Carruth // Use up FileID #0 as an invalid expansion. 343925296b4SDouglas Gregor NextLocalOffset = 0; 34492a47bd9SArgyrios Kyrtzidis CurrentLoadedOffset = MaxLoadedOffset; 345115b077fSChandler Carruth createExpansionLoc(SourceLocation(), SourceLocation(), SourceLocation(), 1); 346b5fba6f8SChris Lattner } 347b5fba6f8SChris Lattner 348168db924SDuncan P. N. Exon Smith bool SourceManager::isMainFile(const FileEntry &SourceFile) { 34911d612acSAlex Lorenz assert(MainFileID.isValid() && "expected initialized SourceManager"); 350168db924SDuncan P. N. Exon Smith if (auto *FE = getFileEntryForID(MainFileID)) 35111d612acSAlex Lorenz return FE->getUID() == SourceFile.getUID(); 352168db924SDuncan P. N. Exon Smith return false; 35311d612acSAlex Lorenz } 35411d612acSAlex Lorenz 355ab75597dSRichard Smith void SourceManager::initializeForReplay(const SourceManager &Old) { 356ab75597dSRichard Smith assert(MainFileID.isInvalid() && "expected uninitialized SourceManager"); 357ab75597dSRichard Smith 358ab75597dSRichard Smith auto CloneContentCache = [&](const ContentCache *Cache) -> ContentCache * { 359ab75597dSRichard Smith auto *Clone = new (ContentCacheAlloc.Allocate<ContentCache>()) ContentCache; 360ab75597dSRichard Smith Clone->OrigEntry = Cache->OrigEntry; 361ab75597dSRichard Smith Clone->ContentsEntry = Cache->ContentsEntry; 362ab75597dSRichard Smith Clone->BufferOverridden = Cache->BufferOverridden; 363f5848190SDuncan P. N. Exon Smith Clone->IsFileVolatile = Cache->IsFileVolatile; 364ab75597dSRichard Smith Clone->IsTransient = Cache->IsTransient; 365156e8b37SDuncan P. N. Exon Smith Clone->setUnownedBuffer(Cache->getBufferIfLoaded()); 366ab75597dSRichard Smith return Clone; 367ab75597dSRichard Smith }; 368ab75597dSRichard Smith 369ab75597dSRichard Smith // Ensure all SLocEntries are loaded from the external source. 370ab75597dSRichard Smith for (unsigned I = 0, N = Old.LoadedSLocEntryTable.size(); I != N; ++I) 371ab75597dSRichard Smith if (!Old.SLocEntryLoaded[I]) 372ab75597dSRichard Smith Old.loadSLocEntry(I, nullptr); 373ab75597dSRichard Smith 374ab75597dSRichard Smith // Inherit any content cache data from the old source manager. 375ab75597dSRichard Smith for (auto &FileInfo : Old.FileInfos) { 376ab75597dSRichard Smith SrcMgr::ContentCache *&Slot = FileInfos[FileInfo.first]; 377ab75597dSRichard Smith if (Slot) 378ab75597dSRichard Smith continue; 379ab75597dSRichard Smith Slot = CloneContentCache(FileInfo.second); 380ab75597dSRichard Smith } 381ab75597dSRichard Smith } 382ab75597dSRichard Smith 3834fa23625SChris Lattner /// getOrCreateContentCache - Create or return a cached ContentCache for the 3844fa23625SChris Lattner /// specified file. 3854fa23625SChris Lattner const ContentCache * 3866d7833f1SArgyrios Kyrtzidis SourceManager::getOrCreateContentCache(const FileEntry *FileEnt, 3876d7833f1SArgyrios Kyrtzidis bool isSystemFile) { 3887a51313dSChris Lattner assert(FileEnt && "Didn't specify a file entry to use?"); 3894fa23625SChris Lattner 3907a51313dSChris Lattner // Do we already have information about this file? 391c8233df6SChris Lattner ContentCache *&Entry = FileInfos[FileEnt]; 392c8233df6SChris Lattner if (Entry) return Entry; 3937a51313dSChris Lattner 39447c48087SChandler Carruth // Nope, create a new Cache entry. 39547c48087SChandler Carruth Entry = ContentCacheAlloc.Allocate<ContentCache>(); 39611e6f0a6SArgyrios Kyrtzidis 3976eec06d0SArgyrios Kyrtzidis if (OverriddenFilesInfo) { 39811e6f0a6SArgyrios Kyrtzidis // If the file contents are overridden with contents from another file, 39911e6f0a6SArgyrios Kyrtzidis // pass that file to ContentCache. 40011e6f0a6SArgyrios Kyrtzidis llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator 4016eec06d0SArgyrios Kyrtzidis overI = OverriddenFilesInfo->OverriddenFiles.find(FileEnt); 4026eec06d0SArgyrios Kyrtzidis if (overI == OverriddenFilesInfo->OverriddenFiles.end()) 403c8233df6SChris Lattner new (Entry) ContentCache(FileEnt); 40411e6f0a6SArgyrios Kyrtzidis else 40597d3a38cSArgyrios Kyrtzidis new (Entry) ContentCache(OverridenFilesKeepOriginalName ? FileEnt 40697d3a38cSArgyrios Kyrtzidis : overI->second, 40797d3a38cSArgyrios Kyrtzidis overI->second); 4086eec06d0SArgyrios Kyrtzidis } else { 4096eec06d0SArgyrios Kyrtzidis new (Entry) ContentCache(FileEnt); 4106eec06d0SArgyrios Kyrtzidis } 41111e6f0a6SArgyrios Kyrtzidis 412f5848190SDuncan P. N. Exon Smith Entry->IsFileVolatile = UserFilesAreVolatile && !isSystemFile; 413a8cfffa3SRichard Smith Entry->IsTransient = FilesAreTransient; 4146d7833f1SArgyrios Kyrtzidis 415c8233df6SChris Lattner return Entry; 4167a51313dSChris Lattner } 4177a51313dSChris Lattner 4186d9bc278SRichard Smith /// Create a new ContentCache for the specified memory buffer. 4196d9bc278SRichard Smith /// This does no caching. 42051d1d585SDuncan P. N. Exon Smith const ContentCache *SourceManager::createMemBufferContentCache( 42151d1d585SDuncan P. N. Exon Smith std::unique_ptr<llvm::MemoryBuffer> Buffer) { 42247c48087SChandler Carruth // Add a new ContentCache to the MemBufferInfos list and return it. 42347c48087SChandler Carruth ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>(); 424c8233df6SChris Lattner new (Entry) ContentCache(); 425c8233df6SChris Lattner MemBufferInfos.push_back(Entry); 42629631451SDuncan P. N. Exon Smith Entry->setBuffer(std::move(Buffer)); 427c8233df6SChris Lattner return Entry; 4287a51313dSChris Lattner } 4297a51313dSChris Lattner 430969fdfddSArgyrios Kyrtzidis const SrcMgr::SLocEntry &SourceManager::loadSLocEntry(unsigned Index, 431969fdfddSArgyrios Kyrtzidis bool *Invalid) const { 432969fdfddSArgyrios Kyrtzidis assert(!SLocEntryLoaded[Index]); 433969fdfddSArgyrios Kyrtzidis if (ExternalSLocEntries->ReadSLocEntry(-(static_cast<int>(Index) + 2))) { 434969fdfddSArgyrios Kyrtzidis if (Invalid) 435969fdfddSArgyrios Kyrtzidis *Invalid = true; 436969fdfddSArgyrios Kyrtzidis // If the file of the SLocEntry changed we could still have loaded it. 437969fdfddSArgyrios Kyrtzidis if (!SLocEntryLoaded[Index]) { 438969fdfddSArgyrios Kyrtzidis // Try to recover; create a SLocEntry so the rest of clang can handle it. 4394dc5573aSAlex Lorenz LoadedSLocEntryTable[Index] = SLocEntry::get( 44074a87834SDuncan P. N. Exon Smith 0, FileInfo::get(SourceLocation(), *getFakeContentCacheForRecovery(), 4414dc5573aSAlex Lorenz SrcMgr::C_User, "")); 442969fdfddSArgyrios Kyrtzidis } 443969fdfddSArgyrios Kyrtzidis } 444969fdfddSArgyrios Kyrtzidis 445969fdfddSArgyrios Kyrtzidis return LoadedSLocEntryTable[Index]; 446969fdfddSArgyrios Kyrtzidis } 447969fdfddSArgyrios Kyrtzidis 448925296b4SDouglas Gregor std::pair<int, unsigned> 449925296b4SDouglas Gregor SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries, 450925296b4SDouglas Gregor unsigned TotalSize) { 451925296b4SDouglas Gregor assert(ExternalSLocEntries && "Don't have an external sloc source"); 45278d81ecfSRichard Smith // Make sure we're not about to run out of source locations. 45378d81ecfSRichard Smith if (CurrentLoadedOffset - TotalSize < NextLocalOffset) 45478d81ecfSRichard Smith return std::make_pair(0, 0); 455925296b4SDouglas Gregor LoadedSLocEntryTable.resize(LoadedSLocEntryTable.size() + NumSLocEntries); 456925296b4SDouglas Gregor SLocEntryLoaded.resize(LoadedSLocEntryTable.size()); 457925296b4SDouglas Gregor CurrentLoadedOffset -= TotalSize; 458925296b4SDouglas Gregor int ID = LoadedSLocEntryTable.size(); 459925296b4SDouglas Gregor return std::make_pair(-ID - 1, CurrentLoadedOffset); 4600bc12935SDouglas Gregor } 4610bc12935SDouglas Gregor 4629fc8faf9SAdrian Prantl /// As part of recovering from missing or changed content, produce a 46349f754f4SDouglas Gregor /// fake, non-empty buffer. 46466cc07b4SDavid Blaikie llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const { 46549f754f4SDouglas Gregor if (!FakeBufferForRecovery) 466d87f8d76SRafael Espindola FakeBufferForRecovery = 467d87f8d76SRafael Espindola llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>"); 46849f754f4SDouglas Gregor 469e0f6d886SRafael Espindola return FakeBufferForRecovery.get(); 47049f754f4SDouglas Gregor } 471258ae54aSDouglas Gregor 4729fc8faf9SAdrian Prantl /// As part of recovering from missing or changed content, produce a 473969fdfddSArgyrios Kyrtzidis /// fake content cache. 474969fdfddSArgyrios Kyrtzidis const SrcMgr::ContentCache * 475969fdfddSArgyrios Kyrtzidis SourceManager::getFakeContentCacheForRecovery() const { 476969fdfddSArgyrios Kyrtzidis if (!FakeContentCacheForRecovery) { 4772b3d49b6SJonas Devlieghere FakeContentCacheForRecovery = std::make_unique<SrcMgr::ContentCache>(); 478156e8b37SDuncan P. N. Exon Smith FakeContentCacheForRecovery->setUnownedBuffer( 479156e8b37SDuncan P. N. Exon Smith getFakeBufferForRecovery()->getMemBufferRef()); 480969fdfddSArgyrios Kyrtzidis } 481e0f6d886SRafael Espindola return FakeContentCacheForRecovery.get(); 482969fdfddSArgyrios Kyrtzidis } 483969fdfddSArgyrios Kyrtzidis 4849fc8faf9SAdrian Prantl /// Returns the previous in-order FileID or an invalid FileID if there 485065d720cSArgyrios Kyrtzidis /// is no previous one. 486065d720cSArgyrios Kyrtzidis FileID SourceManager::getPreviousFileID(FileID FID) const { 487065d720cSArgyrios Kyrtzidis if (FID.isInvalid()) 488065d720cSArgyrios Kyrtzidis return FileID(); 489065d720cSArgyrios Kyrtzidis 490065d720cSArgyrios Kyrtzidis int ID = FID.ID; 491065d720cSArgyrios Kyrtzidis if (ID == -1) 492065d720cSArgyrios Kyrtzidis return FileID(); 493065d720cSArgyrios Kyrtzidis 494065d720cSArgyrios Kyrtzidis if (ID > 0) { 495065d720cSArgyrios Kyrtzidis if (ID-1 == 0) 496065d720cSArgyrios Kyrtzidis return FileID(); 497065d720cSArgyrios Kyrtzidis } else if (unsigned(-(ID-1) - 2) >= LoadedSLocEntryTable.size()) { 498065d720cSArgyrios Kyrtzidis return FileID(); 499065d720cSArgyrios Kyrtzidis } 500065d720cSArgyrios Kyrtzidis 501065d720cSArgyrios Kyrtzidis return FileID::get(ID-1); 502065d720cSArgyrios Kyrtzidis } 503065d720cSArgyrios Kyrtzidis 5049fc8faf9SAdrian Prantl /// Returns the next in-order FileID or an invalid FileID if there is 505065d720cSArgyrios Kyrtzidis /// no next one. 506065d720cSArgyrios Kyrtzidis FileID SourceManager::getNextFileID(FileID FID) const { 507065d720cSArgyrios Kyrtzidis if (FID.isInvalid()) 508065d720cSArgyrios Kyrtzidis return FileID(); 509065d720cSArgyrios Kyrtzidis 510065d720cSArgyrios Kyrtzidis int ID = FID.ID; 511065d720cSArgyrios Kyrtzidis if (ID > 0) { 512065d720cSArgyrios Kyrtzidis if (unsigned(ID+1) >= local_sloc_entry_size()) 513065d720cSArgyrios Kyrtzidis return FileID(); 514065d720cSArgyrios Kyrtzidis } else if (ID+1 >= -1) { 515065d720cSArgyrios Kyrtzidis return FileID(); 516065d720cSArgyrios Kyrtzidis } 517065d720cSArgyrios Kyrtzidis 518065d720cSArgyrios Kyrtzidis return FileID::get(ID+1); 519065d720cSArgyrios Kyrtzidis } 520065d720cSArgyrios Kyrtzidis 5214fa23625SChris Lattner //===----------------------------------------------------------------------===// 52264ee782eSChandler Carruth // Methods to create new FileID's and macro expansions. 5234fa23625SChris Lattner //===----------------------------------------------------------------------===// 5247a51313dSChris Lattner 525e08464fbSReid Kleckner /// Create a new FileID that represents the specified file 526e08464fbSReid Kleckner /// being \#included from the specified IncludePosition. 527e08464fbSReid Kleckner /// 528e08464fbSReid Kleckner /// This translates NULL into standard input. 529e08464fbSReid Kleckner FileID SourceManager::createFileID(const FileEntry *SourceFile, 530e08464fbSReid Kleckner SourceLocation IncludePos, 531e08464fbSReid Kleckner SrcMgr::CharacteristicKind FileCharacter, 532e08464fbSReid Kleckner int LoadedID, unsigned LoadedOffset) { 533e08464fbSReid Kleckner assert(SourceFile && "Null source file!"); 534e08464fbSReid Kleckner const SrcMgr::ContentCache *IR = 535e08464fbSReid Kleckner getOrCreateContentCache(SourceFile, isSystem(FileCharacter)); 536e08464fbSReid Kleckner assert(IR && "getOrCreateContentCache() cannot return NULL"); 53774a87834SDuncan P. N. Exon Smith return createFileIDImpl(*IR, SourceFile->getName(), IncludePos, FileCharacter, 538e08464fbSReid Kleckner LoadedID, LoadedOffset); 539e08464fbSReid Kleckner } 540e08464fbSReid Kleckner 541e08464fbSReid Kleckner FileID SourceManager::createFileID(FileEntryRef SourceFile, 542e08464fbSReid Kleckner SourceLocation IncludePos, 543e08464fbSReid Kleckner SrcMgr::CharacteristicKind FileCharacter, 544e08464fbSReid Kleckner int LoadedID, unsigned LoadedOffset) { 545e08464fbSReid Kleckner const SrcMgr::ContentCache *IR = getOrCreateContentCache( 546e08464fbSReid Kleckner &SourceFile.getFileEntry(), isSystem(FileCharacter)); 547e08464fbSReid Kleckner assert(IR && "getOrCreateContentCache() cannot return NULL"); 54874a87834SDuncan P. N. Exon Smith return createFileIDImpl(*IR, SourceFile.getName(), IncludePos, FileCharacter, 549e08464fbSReid Kleckner LoadedID, LoadedOffset); 550e08464fbSReid Kleckner } 551e08464fbSReid Kleckner 552e08464fbSReid Kleckner /// Create a new FileID that represents the specified memory buffer. 553e08464fbSReid Kleckner /// 554e08464fbSReid Kleckner /// This does no caching of the buffer and takes ownership of the 555e08464fbSReid Kleckner /// MemoryBuffer, so only pass a MemoryBuffer to this once. 556e08464fbSReid Kleckner FileID SourceManager::createFileID(std::unique_ptr<llvm::MemoryBuffer> Buffer, 557e08464fbSReid Kleckner SrcMgr::CharacteristicKind FileCharacter, 558e08464fbSReid Kleckner int LoadedID, unsigned LoadedOffset, 559e08464fbSReid Kleckner SourceLocation IncludeLoc) { 560e08464fbSReid Kleckner StringRef Name = Buffer->getBufferIdentifier(); 56174a87834SDuncan P. N. Exon Smith return createFileIDImpl(*createMemBufferContentCache(std::move(Buffer)), Name, 56251d1d585SDuncan P. N. Exon Smith IncludeLoc, FileCharacter, LoadedID, LoadedOffset); 563e08464fbSReid Kleckner } 564e08464fbSReid Kleckner 565e08464fbSReid Kleckner /// Create a new FileID that represents the specified memory buffer. 566e08464fbSReid Kleckner /// 567e08464fbSReid Kleckner /// This does not take ownership of the MemoryBuffer. The memory buffer must 568e08464fbSReid Kleckner /// outlive the SourceManager. 56951d1d585SDuncan P. N. Exon Smith FileID SourceManager::createFileID(const llvm::MemoryBufferRef &Buffer, 570e08464fbSReid Kleckner SrcMgr::CharacteristicKind FileCharacter, 571e08464fbSReid Kleckner int LoadedID, unsigned LoadedOffset, 572e08464fbSReid Kleckner SourceLocation IncludeLoc) { 57351d1d585SDuncan P. N. Exon Smith return createFileID(llvm::MemoryBuffer::getMemBuffer(Buffer), FileCharacter, 57451d1d585SDuncan P. N. Exon Smith LoadedID, LoadedOffset, IncludeLoc); 575e08464fbSReid Kleckner } 576e08464fbSReid Kleckner 577e08464fbSReid Kleckner /// Get the FileID for \p SourceFile if it exists. Otherwise, create a 578e08464fbSReid Kleckner /// new FileID for the \p SourceFile. 579e08464fbSReid Kleckner FileID 580e08464fbSReid Kleckner SourceManager::getOrCreateFileID(const FileEntry *SourceFile, 581e08464fbSReid Kleckner SrcMgr::CharacteristicKind FileCharacter) { 582e08464fbSReid Kleckner FileID ID = translateFile(SourceFile); 583e08464fbSReid Kleckner return ID.isValid() ? ID : createFileID(SourceFile, SourceLocation(), 584e08464fbSReid Kleckner FileCharacter); 585e08464fbSReid Kleckner } 586e08464fbSReid Kleckner 587ce46f02aSDan Gohman /// createFileID - Create a new FileID for the specified ContentCache and 5887a51313dSChris Lattner /// include position. This works regardless of whether the ContentCache 5897a51313dSChris Lattner /// corresponds to a file or some other input source. 59074a87834SDuncan P. N. Exon Smith FileID SourceManager::createFileIDImpl(const ContentCache &File, 59174a87834SDuncan P. N. Exon Smith StringRef Filename, 5924c311643SNico Weber SourceLocation IncludePos, 593258ae54aSDouglas Gregor SrcMgr::CharacteristicKind FileCharacter, 594925296b4SDouglas Gregor int LoadedID, unsigned LoadedOffset) { 595925296b4SDouglas Gregor if (LoadedID < 0) { 596925296b4SDouglas Gregor assert(LoadedID != -1 && "Loading sentinel FileID"); 597925296b4SDouglas Gregor unsigned Index = unsigned(-LoadedID) - 2; 598925296b4SDouglas Gregor assert(Index < LoadedSLocEntryTable.size() && "FileID out of range"); 599925296b4SDouglas Gregor assert(!SLocEntryLoaded[Index] && "FileID already loaded"); 6004dc5573aSAlex Lorenz LoadedSLocEntryTable[Index] = SLocEntry::get( 6014dc5573aSAlex Lorenz LoadedOffset, FileInfo::get(IncludePos, File, FileCharacter, Filename)); 602925296b4SDouglas Gregor SLocEntryLoaded[Index] = true; 603925296b4SDouglas Gregor return FileID::get(LoadedID); 604258ae54aSDouglas Gregor } 60574a87834SDuncan P. N. Exon Smith unsigned FileSize = File.getSize(); 606bce360b7SDiogo Sampaio if (!(NextLocalOffset + FileSize + 1 > NextLocalOffset && 607bce360b7SDiogo Sampaio NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset)) { 608bce360b7SDiogo Sampaio Diag.Report(IncludePos, diag::err_include_too_large); 609bce360b7SDiogo Sampaio return FileID(); 610bce360b7SDiogo Sampaio } 6114dc5573aSAlex Lorenz LocalSLocEntryTable.push_back( 6124dc5573aSAlex Lorenz SLocEntry::get(NextLocalOffset, 6134dc5573aSAlex Lorenz FileInfo::get(IncludePos, File, FileCharacter, Filename))); 614925296b4SDouglas Gregor // We do a +1 here because we want a SourceLocation that means "the end of the 615925296b4SDouglas Gregor // file", e.g. for the "no newline at the end of the file" diagnostic. 616925296b4SDouglas Gregor NextLocalOffset += FileSize + 1; 6174fa23625SChris Lattner 6184fa23625SChris Lattner // Set LastFileIDLookup to the newly created file. The next getFileID call is 6194fa23625SChris Lattner // almost guaranteed to be from that file. 620925296b4SDouglas Gregor FileID FID = FileID::get(LocalSLocEntryTable.size()-1); 6210152c6cbSArgyrios Kyrtzidis return LastFileIDLookup = FID; 6227a51313dSChris Lattner } 6237a51313dSChris Lattner 624402bb388SChandler Carruth SourceLocation 625115b077fSChandler Carruth SourceManager::createMacroArgExpansionLoc(SourceLocation SpellingLoc, 626115b077fSChandler Carruth SourceLocation ExpansionLoc, 627402bb388SChandler Carruth unsigned TokLength) { 62873ee5d7fSChandler Carruth ExpansionInfo Info = ExpansionInfo::createForMacroArg(SpellingLoc, 62973ee5d7fSChandler Carruth ExpansionLoc); 63073ee5d7fSChandler Carruth return createExpansionLocImpl(Info, TokLength); 631402bb388SChandler Carruth } 632402bb388SChandler Carruth 633115b077fSChandler Carruth SourceLocation 634115b077fSChandler Carruth SourceManager::createExpansionLoc(SourceLocation SpellingLoc, 635115b077fSChandler Carruth SourceLocation ExpansionLocStart, 636115b077fSChandler Carruth SourceLocation ExpansionLocEnd, 637258ae54aSDouglas Gregor unsigned TokLength, 638b5f8171aSRichard Smith bool ExpansionIsTokenRange, 639925296b4SDouglas Gregor int LoadedID, 640925296b4SDouglas Gregor unsigned LoadedOffset) { 641b5f8171aSRichard Smith ExpansionInfo Info = ExpansionInfo::create( 642b5f8171aSRichard Smith SpellingLoc, ExpansionLocStart, ExpansionLocEnd, ExpansionIsTokenRange); 64373ee5d7fSChandler Carruth return createExpansionLocImpl(Info, TokLength, LoadedID, LoadedOffset); 644402bb388SChandler Carruth } 645402bb388SChandler Carruth 646b5f8171aSRichard Smith SourceLocation SourceManager::createTokenSplitLoc(SourceLocation Spelling, 647b5f8171aSRichard Smith SourceLocation TokenStart, 648b5f8171aSRichard Smith SourceLocation TokenEnd) { 649b5f8171aSRichard Smith assert(getFileID(TokenStart) == getFileID(TokenEnd) && 650b5f8171aSRichard Smith "token spans multiple files"); 651b5f8171aSRichard Smith return createExpansionLocImpl( 652b5f8171aSRichard Smith ExpansionInfo::createForTokenSplit(Spelling, TokenStart, TokenEnd), 653b5f8171aSRichard Smith TokenEnd.getOffset() - TokenStart.getOffset()); 654b5f8171aSRichard Smith } 655b5f8171aSRichard Smith 656402bb388SChandler Carruth SourceLocation 65773ee5d7fSChandler Carruth SourceManager::createExpansionLocImpl(const ExpansionInfo &Info, 658402bb388SChandler Carruth unsigned TokLength, 659925296b4SDouglas Gregor int LoadedID, 660925296b4SDouglas Gregor unsigned LoadedOffset) { 661925296b4SDouglas Gregor if (LoadedID < 0) { 662925296b4SDouglas Gregor assert(LoadedID != -1 && "Loading sentinel FileID"); 663925296b4SDouglas Gregor unsigned Index = unsigned(-LoadedID) - 2; 664925296b4SDouglas Gregor assert(Index < LoadedSLocEntryTable.size() && "FileID out of range"); 665925296b4SDouglas Gregor assert(!SLocEntryLoaded[Index] && "FileID already loaded"); 66673ee5d7fSChandler Carruth LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset, Info); 667925296b4SDouglas Gregor SLocEntryLoaded[Index] = true; 668925296b4SDouglas Gregor return SourceLocation::getMacroLoc(LoadedOffset); 669258ae54aSDouglas Gregor } 67073ee5d7fSChandler Carruth LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, Info)); 671925296b4SDouglas Gregor assert(NextLocalOffset + TokLength + 1 > NextLocalOffset && 672925296b4SDouglas Gregor NextLocalOffset + TokLength + 1 <= CurrentLoadedOffset && 673925296b4SDouglas Gregor "Ran out of source locations!"); 674925296b4SDouglas Gregor // See createFileID for that +1. 675925296b4SDouglas Gregor NextLocalOffset += TokLength + 1; 676925296b4SDouglas Gregor return SourceLocation::getMacroLoc(NextLocalOffset - (TokLength + 1)); 6777a51313dSChris Lattner } 6787a51313dSChris Lattner 6792dc7e0c6SDuncan P. N. Exon Smith llvm::Optional<llvm::MemoryBufferRef> 6802dc7e0c6SDuncan P. N. Exon Smith SourceManager::getMemoryBufferForFileOrNone(const FileEntry *File) { 68153ad6b94SDouglas Gregor const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); 682802b7760SDouglas Gregor assert(IR && "getOrCreateContentCache() cannot return NULL"); 6832dc7e0c6SDuncan P. N. Exon Smith return IR->getBufferOrNone(Diag, getFileManager(), SourceLocation()); 68453ad6b94SDouglas Gregor } 68553ad6b94SDouglas Gregor 68629631451SDuncan P. N. Exon Smith void SourceManager::overrideFileContents( 68729631451SDuncan P. N. Exon Smith const FileEntry *SourceFile, std::unique_ptr<llvm::MemoryBuffer> Buffer) { 68829631451SDuncan P. N. Exon Smith auto *IR = 68929631451SDuncan P. N. Exon Smith const_cast<SrcMgr::ContentCache *>(getOrCreateContentCache(SourceFile)); 6905d223dcbSDan Gohman assert(IR && "getOrCreateContentCache() cannot return NULL"); 69153ad6b94SDouglas Gregor 69229631451SDuncan P. N. Exon Smith IR->setBuffer(std::move(Buffer)); 69329631451SDuncan P. N. Exon Smith IR->BufferOverridden = true; 6946eec06d0SArgyrios Kyrtzidis 6956eec06d0SArgyrios Kyrtzidis getOverriddenFilesInfo().OverriddenFilesWithBuffer.insert(SourceFile); 69653ad6b94SDouglas Gregor } 69753ad6b94SDouglas Gregor 69811e6f0a6SArgyrios Kyrtzidis void SourceManager::overrideFileContents(const FileEntry *SourceFile, 69911e6f0a6SArgyrios Kyrtzidis const FileEntry *NewFile) { 70011e6f0a6SArgyrios Kyrtzidis assert(SourceFile->getSize() == NewFile->getSize() && 70111e6f0a6SArgyrios Kyrtzidis "Different sizes, use the FileManager to create a virtual file with " 70211e6f0a6SArgyrios Kyrtzidis "the correct size"); 70311e6f0a6SArgyrios Kyrtzidis assert(FileInfos.count(SourceFile) == 0 && 70411e6f0a6SArgyrios Kyrtzidis "This function should be called at the initialization stage, before " 70511e6f0a6SArgyrios Kyrtzidis "any parsing occurs."); 7066eec06d0SArgyrios Kyrtzidis getOverriddenFilesInfo().OverriddenFiles[SourceFile] = NewFile; 7076eec06d0SArgyrios Kyrtzidis } 7086eec06d0SArgyrios Kyrtzidis 709e1b7f22bSDuncan P. N. Exon Smith const FileEntry * 710e1b7f22bSDuncan P. N. Exon Smith SourceManager::bypassFileContentsOverride(const FileEntry &File) { 711e1b7f22bSDuncan P. N. Exon Smith assert(isFileOverridden(&File)); 712e1b7f22bSDuncan P. N. Exon Smith llvm::Optional<FileEntryRef> BypassFile = 713e1b7f22bSDuncan P. N. Exon Smith FileMgr.getBypassFile(FileEntryRef(File.getName(), File)); 7146eec06d0SArgyrios Kyrtzidis 715e1b7f22bSDuncan P. N. Exon Smith // If the file can't be found in the FS, give up. 716e1b7f22bSDuncan P. N. Exon Smith if (!BypassFile) 717e1b7f22bSDuncan P. N. Exon Smith return nullptr; 7186eec06d0SArgyrios Kyrtzidis 719e1b7f22bSDuncan P. N. Exon Smith const FileEntry *FE = &BypassFile->getFileEntry(); 720e1b7f22bSDuncan P. N. Exon Smith (void)getOrCreateContentCache(FE); 721e1b7f22bSDuncan P. N. Exon Smith return FE; 72211e6f0a6SArgyrios Kyrtzidis } 72311e6f0a6SArgyrios Kyrtzidis 724a8cfffa3SRichard Smith void SourceManager::setFileIsTransient(const FileEntry *File) { 725fb1e7f7dSRichard Smith const SrcMgr::ContentCache *CC = getOrCreateContentCache(File); 726a8cfffa3SRichard Smith const_cast<SrcMgr::ContentCache *>(CC)->IsTransient = true; 727fb1e7f7dSRichard Smith } 728fb1e7f7dSRichard Smith 729cf593d22SDuncan P. N. Exon Smith Optional<StringRef> 730cf593d22SDuncan P. N. Exon Smith SourceManager::getNonBuiltinFilenameForID(FileID FID) const { 731b6c6daa9SDuncan P. N. Exon Smith if (const SrcMgr::SLocEntry *Entry = getSLocEntryForFile(FID)) 73274a87834SDuncan P. N. Exon Smith if (Entry->getFile().getContentCache().OrigEntry) 733cf593d22SDuncan P. N. Exon Smith return Entry->getFile().getName(); 734e08464fbSReid Kleckner return None; 735e08464fbSReid Kleckner } 736e08464fbSReid Kleckner 7370e62c1ccSChris Lattner StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { 738d758f79eSDuncan P. N. Exon Smith auto B = getBufferDataOrNone(FID); 73986af9844SDouglas Gregor if (Invalid) 740d758f79eSDuncan P. N. Exon Smith *Invalid = !B; 741d758f79eSDuncan P. N. Exon Smith return B ? *B : "<<<<<INVALID SOURCE LOCATION>>>>>"; 74286af9844SDouglas Gregor } 74386af9844SDouglas Gregor 744d758f79eSDuncan P. N. Exon Smith llvm::Optional<StringRef> 745d758f79eSDuncan P. N. Exon Smith SourceManager::getBufferDataIfLoaded(FileID FID) const { 746b6c6daa9SDuncan P. N. Exon Smith if (const SrcMgr::SLocEntry *Entry = getSLocEntryForFile(FID)) 74774a87834SDuncan P. N. Exon Smith return Entry->getFile().getContentCache().getBufferDataIfLoaded(); 748d758f79eSDuncan P. N. Exon Smith return None; 749d758f79eSDuncan P. N. Exon Smith } 750d758f79eSDuncan P. N. Exon Smith 751d758f79eSDuncan P. N. Exon Smith llvm::Optional<StringRef> SourceManager::getBufferDataOrNone(FileID FID) const { 752b6c6daa9SDuncan P. N. Exon Smith if (const SrcMgr::SLocEntry *Entry = getSLocEntryForFile(FID)) 75374a87834SDuncan P. N. Exon Smith if (auto B = Entry->getFile().getContentCache().getBufferOrNone( 754d758f79eSDuncan P. N. Exon Smith Diag, getFileManager(), SourceLocation())) 755d758f79eSDuncan P. N. Exon Smith return B->getBuffer(); 756d758f79eSDuncan P. N. Exon Smith return None; 757802b7760SDouglas Gregor } 758d32480d3SChris Lattner 759153a0f1fSChris Lattner //===----------------------------------------------------------------------===// 7604fa23625SChris Lattner // SourceLocation manipulation methods. 761153a0f1fSChris Lattner //===----------------------------------------------------------------------===// 7624fa23625SChris Lattner 7639fc8faf9SAdrian Prantl /// Return the FileID for a SourceLocation. 7644fa23625SChris Lattner /// 765925296b4SDouglas Gregor /// This is the cache-miss path of getFileID. Not as hot as that function, but 766925296b4SDouglas Gregor /// still very important. It is responsible for finding the entry in the 767925296b4SDouglas Gregor /// SLocEntry tables that contains the specified location. 7684fa23625SChris Lattner FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { 76949f754f4SDouglas Gregor if (!SLocOffset) 77049f754f4SDouglas Gregor return FileID::get(0); 7714fa23625SChris Lattner 772925296b4SDouglas Gregor // Now it is time to search for the correct file. See where the SLocOffset 773925296b4SDouglas Gregor // sits in the global view and consult local or loaded buffers for it. 774925296b4SDouglas Gregor if (SLocOffset < NextLocalOffset) 775925296b4SDouglas Gregor return getFileIDLocal(SLocOffset); 776925296b4SDouglas Gregor return getFileIDLoaded(SLocOffset); 777925296b4SDouglas Gregor } 778925296b4SDouglas Gregor 7799fc8faf9SAdrian Prantl /// Return the FileID for a SourceLocation with a low offset. 780925296b4SDouglas Gregor /// 781925296b4SDouglas Gregor /// This function knows that the SourceLocation is in a local buffer, not a 782925296b4SDouglas Gregor /// loaded one. 783925296b4SDouglas Gregor FileID SourceManager::getFileIDLocal(unsigned SLocOffset) const { 784925296b4SDouglas Gregor assert(SLocOffset < NextLocalOffset && "Bad function choice"); 785925296b4SDouglas Gregor 7864fa23625SChris Lattner // After the first and second level caches, I see two common sorts of 78764ee782eSChandler Carruth // behavior: 1) a lot of searched FileID's are "near" the cached file 78864ee782eSChandler Carruth // location or are "near" the cached expansion location. 2) others are just 7894fa23625SChris Lattner // completely random and may be a very long way away. 7904fa23625SChris Lattner // 7914fa23625SChris Lattner // To handle this, we do a linear search for up to 8 steps to catch #1 quickly 7924fa23625SChris Lattner // then we fall back to a less cache efficient, but more scalable, binary 7934fa23625SChris Lattner // search to find the location. 7944fa23625SChris Lattner 7954fa23625SChris Lattner // See if this is near the file point - worst case we start scanning from the 7964fa23625SChris Lattner // most newly created FileID. 7972999b77fSBenjamin Kramer const SrcMgr::SLocEntry *I; 7984fa23625SChris Lattner 799925296b4SDouglas Gregor if (LastFileIDLookup.ID < 0 || 800925296b4SDouglas Gregor LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) { 8014fa23625SChris Lattner // Neither loc prunes our search. 802925296b4SDouglas Gregor I = LocalSLocEntryTable.end(); 8034fa23625SChris Lattner } else { 8044fa23625SChris Lattner // Perhaps it is near the file point. 805925296b4SDouglas Gregor I = LocalSLocEntryTable.begin()+LastFileIDLookup.ID; 8064fa23625SChris Lattner } 8074fa23625SChris Lattner 8084fa23625SChris Lattner // Find the FileID that contains this. "I" is an iterator that points to a 8094fa23625SChris Lattner // FileID whose offset is known to be larger than SLocOffset. 8104fa23625SChris Lattner unsigned NumProbes = 0; 811918e0ca7SEugene Zelenko while (true) { 8124fa23625SChris Lattner --I; 8134fa23625SChris Lattner if (I->getOffset() <= SLocOffset) { 814925296b4SDouglas Gregor FileID Res = FileID::get(int(I - LocalSLocEntryTable.begin())); 8157b8cf98bSNick Desaulniers // Remember it. We have good locality across FileID lookups. 8164fa23625SChris Lattner LastFileIDLookup = Res; 8174fa23625SChris Lattner NumLinearScans += NumProbes+1; 8184fa23625SChris Lattner return Res; 8194fa23625SChris Lattner } 8204fa23625SChris Lattner if (++NumProbes == 8) 8214fa23625SChris Lattner break; 8224fa23625SChris Lattner } 8234fa23625SChris Lattner 8244fa23625SChris Lattner // Convert "I" back into an index. We know that it is an entry whose index is 8254fa23625SChris Lattner // larger than the offset we are looking for. 826925296b4SDouglas Gregor unsigned GreaterIndex = I - LocalSLocEntryTable.begin(); 8274fa23625SChris Lattner // LessIndex - This is the lower bound of the range that we're searching. 8284fa23625SChris Lattner // We know that the offset corresponding to the FileID is is less than 8294fa23625SChris Lattner // SLocOffset. 8304fa23625SChris Lattner unsigned LessIndex = 0; 8314fa23625SChris Lattner NumProbes = 0; 832918e0ca7SEugene Zelenko while (true) { 8334fa23625SChris Lattner unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex; 8348cce7af0SNick Desaulniers unsigned MidOffset = getLocalSLocEntry(MiddleIndex).getOffset(); 8354fa23625SChris Lattner 8364fa23625SChris Lattner ++NumProbes; 8374fa23625SChris Lattner 8384fa23625SChris Lattner // If the offset of the midpoint is too large, chop the high side of the 8394fa23625SChris Lattner // range to the midpoint. 8404fa23625SChris Lattner if (MidOffset > SLocOffset) { 8414fa23625SChris Lattner GreaterIndex = MiddleIndex; 8424fa23625SChris Lattner continue; 8434fa23625SChris Lattner } 8444fa23625SChris Lattner 8454fa23625SChris Lattner // If the middle index contains the value, succeed and return. 846408efffbSNick Desaulniers if (MiddleIndex + 1 == LocalSLocEntryTable.size() || 847408efffbSNick Desaulniers SLocOffset < getLocalSLocEntry(MiddleIndex + 1).getOffset()) { 8484fa23625SChris Lattner FileID Res = FileID::get(MiddleIndex); 8494fa23625SChris Lattner 8507b8cf98bSNick Desaulniers // Remember it. We have good locality across FileID lookups. 8514fa23625SChris Lattner LastFileIDLookup = Res; 8524fa23625SChris Lattner NumBinaryProbes += NumProbes; 8534fa23625SChris Lattner return Res; 8544fa23625SChris Lattner } 8554fa23625SChris Lattner 8564fa23625SChris Lattner // Otherwise, move the low-side up to the middle index. 8574fa23625SChris Lattner LessIndex = MiddleIndex; 8584fa23625SChris Lattner } 8594fa23625SChris Lattner } 8604fa23625SChris Lattner 8619fc8faf9SAdrian Prantl /// Return the FileID for a SourceLocation with a high offset. 862925296b4SDouglas Gregor /// 863925296b4SDouglas Gregor /// This function knows that the SourceLocation is in a loaded buffer, not a 864925296b4SDouglas Gregor /// local one. 865925296b4SDouglas Gregor FileID SourceManager::getFileIDLoaded(unsigned SLocOffset) const { 86625029d49SArgyrios Kyrtzidis // Sanity checking, otherwise a bug may lead to hanging in release build. 8678edffaa6SArgyrios Kyrtzidis if (SLocOffset < CurrentLoadedOffset) { 8688edffaa6SArgyrios Kyrtzidis assert(0 && "Invalid SLocOffset or bad function choice"); 86925029d49SArgyrios Kyrtzidis return FileID(); 8708edffaa6SArgyrios Kyrtzidis } 87125029d49SArgyrios Kyrtzidis 872925296b4SDouglas Gregor // Essentially the same as the local case, but the loaded array is sorted 873925296b4SDouglas Gregor // in the other direction. 874925296b4SDouglas Gregor 875925296b4SDouglas Gregor // First do a linear scan from the last lookup position, if possible. 876925296b4SDouglas Gregor unsigned I; 877925296b4SDouglas Gregor int LastID = LastFileIDLookup.ID; 878925296b4SDouglas Gregor if (LastID >= 0 || getLoadedSLocEntryByID(LastID).getOffset() < SLocOffset) 879925296b4SDouglas Gregor I = 0; 880925296b4SDouglas Gregor else 881925296b4SDouglas Gregor I = (-LastID - 2) + 1; 882925296b4SDouglas Gregor 883925296b4SDouglas Gregor unsigned NumProbes; 884925296b4SDouglas Gregor for (NumProbes = 0; NumProbes < 8; ++NumProbes, ++I) { 885925296b4SDouglas Gregor // Make sure the entry is loaded! 886925296b4SDouglas Gregor const SrcMgr::SLocEntry &E = getLoadedSLocEntry(I); 887925296b4SDouglas Gregor if (E.getOffset() <= SLocOffset) { 888925296b4SDouglas Gregor FileID Res = FileID::get(-int(I) - 2); 889925296b4SDouglas Gregor LastFileIDLookup = Res; 890925296b4SDouglas Gregor NumLinearScans += NumProbes + 1; 891925296b4SDouglas Gregor return Res; 892925296b4SDouglas Gregor } 893925296b4SDouglas Gregor } 894925296b4SDouglas Gregor 895925296b4SDouglas Gregor // Linear scan failed. Do the binary search. Note the reverse sorting of the 896925296b4SDouglas Gregor // table: GreaterIndex is the one where the offset is greater, which is 897925296b4SDouglas Gregor // actually a lower index! 898925296b4SDouglas Gregor unsigned GreaterIndex = I; 899925296b4SDouglas Gregor unsigned LessIndex = LoadedSLocEntryTable.size(); 900925296b4SDouglas Gregor NumProbes = 0; 901918e0ca7SEugene Zelenko while (true) { 902925296b4SDouglas Gregor ++NumProbes; 903925296b4SDouglas Gregor unsigned MiddleIndex = (LessIndex - GreaterIndex) / 2 + GreaterIndex; 904925296b4SDouglas Gregor const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex); 9057dc4f33cSArgyrios Kyrtzidis if (E.getOffset() == 0) 9067dc4f33cSArgyrios Kyrtzidis return FileID(); // invalid entry. 907925296b4SDouglas Gregor 908925296b4SDouglas Gregor ++NumProbes; 909925296b4SDouglas Gregor 910925296b4SDouglas Gregor if (E.getOffset() > SLocOffset) { 9117dc4f33cSArgyrios Kyrtzidis // Sanity checking, otherwise a bug may lead to hanging in release build. 9127dc4f33cSArgyrios Kyrtzidis if (GreaterIndex == MiddleIndex) { 9137dc4f33cSArgyrios Kyrtzidis assert(0 && "binary search missed the entry"); 9147dc4f33cSArgyrios Kyrtzidis return FileID(); 9157dc4f33cSArgyrios Kyrtzidis } 916925296b4SDouglas Gregor GreaterIndex = MiddleIndex; 917925296b4SDouglas Gregor continue; 918925296b4SDouglas Gregor } 919925296b4SDouglas Gregor 920925296b4SDouglas Gregor if (isOffsetInFileID(FileID::get(-int(MiddleIndex) - 2), SLocOffset)) { 921925296b4SDouglas Gregor FileID Res = FileID::get(-int(MiddleIndex) - 2); 922925296b4SDouglas Gregor LastFileIDLookup = Res; 923925296b4SDouglas Gregor NumBinaryProbes += NumProbes; 924925296b4SDouglas Gregor return Res; 925925296b4SDouglas Gregor } 926925296b4SDouglas Gregor 9271ca73445SArgyrios Kyrtzidis // Sanity checking, otherwise a bug may lead to hanging in release build. 9281ca73445SArgyrios Kyrtzidis if (LessIndex == MiddleIndex) { 9291ca73445SArgyrios Kyrtzidis assert(0 && "binary search missed the entry"); 9301ca73445SArgyrios Kyrtzidis return FileID(); 9311ca73445SArgyrios Kyrtzidis } 932925296b4SDouglas Gregor LessIndex = MiddleIndex; 933925296b4SDouglas Gregor } 934925296b4SDouglas Gregor } 935925296b4SDouglas Gregor 936659ac5f0SChris Lattner SourceLocation SourceManager:: 937c84d769cSChandler Carruth getExpansionLocSlowCase(SourceLocation Loc) const { 938659ac5f0SChris Lattner do { 9395647d319SChris Lattner // Note: If Loc indicates an offset into a token that came from a macro 9405647d319SChris Lattner // expansion (e.g. the 5th character of the token) we do not want to add 941ee4c1d12SChandler Carruth // this offset when going to the expansion location. The expansion 9425647d319SChris Lattner // location is the macro invocation, which the offset has nothing to do 9435647d319SChris Lattner // with. This is unlike when we get the spelling loc, because the offset 9445647d319SChris Lattner // directly correspond to the token whose spelling we're inspecting. 945ee4c1d12SChandler Carruth Loc = getSLocEntry(getFileID(Loc)).getExpansion().getExpansionLocStart(); 946659ac5f0SChris Lattner } while (!Loc.isFileID()); 947659ac5f0SChris Lattner 948659ac5f0SChris Lattner return Loc; 949659ac5f0SChris Lattner } 950659ac5f0SChris Lattner 951659ac5f0SChris Lattner SourceLocation SourceManager::getSpellingLocSlowCase(SourceLocation Loc) const { 952659ac5f0SChris Lattner do { 953659ac5f0SChris Lattner std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc); 954ee4c1d12SChandler Carruth Loc = getSLocEntry(LocInfo.first).getExpansion().getSpellingLoc(); 955e6e67deeSArgyrios Kyrtzidis Loc = Loc.getLocWithOffset(LocInfo.second); 956659ac5f0SChris Lattner } while (!Loc.isFileID()); 957659ac5f0SChris Lattner return Loc; 958659ac5f0SChris Lattner } 959659ac5f0SChris Lattner 9607f6b029cSArgyrios Kyrtzidis SourceLocation SourceManager::getFileLocSlowCase(SourceLocation Loc) const { 9617f6b029cSArgyrios Kyrtzidis do { 9627f6b029cSArgyrios Kyrtzidis if (isMacroArgExpansion(Loc)) 9637f6b029cSArgyrios Kyrtzidis Loc = getImmediateSpellingLoc(Loc); 9647f6b029cSArgyrios Kyrtzidis else 965b5f8171aSRichard Smith Loc = getImmediateExpansionRange(Loc).getBegin(); 9667f6b029cSArgyrios Kyrtzidis } while (!Loc.isFileID()); 9677f6b029cSArgyrios Kyrtzidis return Loc; 9687f6b029cSArgyrios Kyrtzidis } 9697f6b029cSArgyrios Kyrtzidis 970659ac5f0SChris Lattner 9714fa23625SChris Lattner std::pair<FileID, unsigned> 972c7ca5218SChandler Carruth SourceManager::getDecomposedExpansionLocSlowCase( 973c8f7e213SArgyrios Kyrtzidis const SrcMgr::SLocEntry *E) const { 97464ee782eSChandler Carruth // If this is an expansion record, walk through all the expansion points. 9754fa23625SChris Lattner FileID FID; 9764fa23625SChris Lattner SourceLocation Loc; 977c8f7e213SArgyrios Kyrtzidis unsigned Offset; 9784fa23625SChris Lattner do { 979ee4c1d12SChandler Carruth Loc = E->getExpansion().getExpansionLocStart(); 9804fa23625SChris Lattner 9814fa23625SChris Lattner FID = getFileID(Loc); 9824fa23625SChris Lattner E = &getSLocEntry(FID); 983c8f7e213SArgyrios Kyrtzidis Offset = Loc.getOffset()-E->getOffset(); 98431af4e08SChris Lattner } while (!Loc.isFileID()); 9854fa23625SChris Lattner 9864fa23625SChris Lattner return std::make_pair(FID, Offset); 9874fa23625SChris Lattner } 9884fa23625SChris Lattner 9894fa23625SChris Lattner std::pair<FileID, unsigned> 9904fa23625SChris Lattner SourceManager::getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, 9914fa23625SChris Lattner unsigned Offset) const { 99264ee782eSChandler Carruth // If this is an expansion record, walk through all the expansion points. 99331af4e08SChris Lattner FileID FID; 99431af4e08SChris Lattner SourceLocation Loc; 99531af4e08SChris Lattner do { 996ee4c1d12SChandler Carruth Loc = E->getExpansion().getSpellingLoc(); 997e6e67deeSArgyrios Kyrtzidis Loc = Loc.getLocWithOffset(Offset); 99831af4e08SChris Lattner 99931af4e08SChris Lattner FID = getFileID(Loc); 10004fa23625SChris Lattner E = &getSLocEntry(FID); 10012797df6aSArgyrios Kyrtzidis Offset = Loc.getOffset()-E->getOffset(); 100231af4e08SChris Lattner } while (!Loc.isFileID()); 100331af4e08SChris Lattner 10044fa23625SChris Lattner return std::make_pair(FID, Offset); 10054fa23625SChris Lattner } 10064fa23625SChris Lattner 10078ad52d50SChris Lattner /// getImmediateSpellingLoc - Given a SourceLocation object, return the 10088ad52d50SChris Lattner /// spelling location referenced by the ID. This is the first level down 10098ad52d50SChris Lattner /// towards the place where the characters that make up the lexed token can be 10108ad52d50SChris Lattner /// found. This should not generally be used by clients. 10118ad52d50SChris Lattner SourceLocation SourceManager::getImmediateSpellingLoc(SourceLocation Loc) const{ 10128ad52d50SChris Lattner if (Loc.isFileID()) return Loc; 10138ad52d50SChris Lattner std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc); 1014ee4c1d12SChandler Carruth Loc = getSLocEntry(LocInfo.first).getExpansion().getSpellingLoc(); 1015e6e67deeSArgyrios Kyrtzidis return Loc.getLocWithOffset(LocInfo.second); 10168ad52d50SChris Lattner } 10178ad52d50SChris Lattner 1018e08464fbSReid Kleckner /// Return the filename of the file containing a SourceLocation. 1019e08464fbSReid Kleckner StringRef SourceManager::getFilename(SourceLocation SpellingLoc) const { 1020e08464fbSReid Kleckner if (const FileEntry *F = getFileEntryForID(getFileID(SpellingLoc))) 1021e08464fbSReid Kleckner return F->getName(); 1022e08464fbSReid Kleckner return StringRef(); 1023e08464fbSReid Kleckner } 1024e08464fbSReid Kleckner 102564ee782eSChandler Carruth /// getImmediateExpansionRange - Loc is required to be an expansion location. 102664ee782eSChandler Carruth /// Return the start/end of the expansion information. 1027b5f8171aSRichard Smith CharSourceRange 1028ca757587SChandler Carruth SourceManager::getImmediateExpansionRange(SourceLocation Loc) const { 102964ee782eSChandler Carruth assert(Loc.isMacroID() && "Not a macro expansion loc!"); 1030ee4c1d12SChandler Carruth const ExpansionInfo &Expansion = getSLocEntry(getFileID(Loc)).getExpansion(); 103173ee5d7fSChandler Carruth return Expansion.getExpansionLocRange(); 10329dc9c206SChris Lattner } 10339dc9c206SChris Lattner 1034441e8fdfSGeorge Karpenkov SourceLocation SourceManager::getTopMacroCallerLoc(SourceLocation Loc) const { 1035441e8fdfSGeorge Karpenkov while (isMacroArgExpansion(Loc)) 1036441e8fdfSGeorge Karpenkov Loc = getImmediateSpellingLoc(Loc); 1037441e8fdfSGeorge Karpenkov return Loc; 1038441e8fdfSGeorge Karpenkov } 1039441e8fdfSGeorge Karpenkov 10406d28d7f2SChandler Carruth /// getExpansionRange - Given a SourceLocation object, return the range of 10416d28d7f2SChandler Carruth /// tokens covered by the expansion in the ultimate file. 1042b5f8171aSRichard Smith CharSourceRange SourceManager::getExpansionRange(SourceLocation Loc) const { 1043b5f8171aSRichard Smith if (Loc.isFileID()) 1044b5f8171aSRichard Smith return CharSourceRange(SourceRange(Loc, Loc), true); 1045f52c0b26SChris Lattner 1046b5f8171aSRichard Smith CharSourceRange Res = getImmediateExpansionRange(Loc); 1047f52c0b26SChris Lattner 104864ee782eSChandler Carruth // Fully resolve the start and end locations to their ultimate expansion 1049f52c0b26SChris Lattner // points. 1050b5f8171aSRichard Smith while (!Res.getBegin().isFileID()) 1051b5f8171aSRichard Smith Res.setBegin(getImmediateExpansionRange(Res.getBegin()).getBegin()); 1052b5f8171aSRichard Smith while (!Res.getEnd().isFileID()) { 1053b5f8171aSRichard Smith CharSourceRange EndRange = getImmediateExpansionRange(Res.getEnd()); 1054b5f8171aSRichard Smith Res.setEnd(EndRange.getEnd()); 1055b5f8171aSRichard Smith Res.setTokenRange(EndRange.isTokenRange()); 1056b5f8171aSRichard Smith } 1057f52c0b26SChris Lattner return Res; 1058f52c0b26SChris Lattner } 1059f52c0b26SChris Lattner 1060c3096249SRichard Trieu bool SourceManager::isMacroArgExpansion(SourceLocation Loc, 1061c3096249SRichard Trieu SourceLocation *StartLoc) const { 1062402bb388SChandler Carruth if (!Loc.isMacroID()) return false; 1063402bb388SChandler Carruth 1064402bb388SChandler Carruth FileID FID = getFileID(Loc); 1065b1e71a7dSMatt Beaumont-Gay const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion(); 1066c3096249SRichard Trieu if (!Expansion.isMacroArgExpansion()) return false; 1067c3096249SRichard Trieu 1068c3096249SRichard Trieu if (StartLoc) 1069c3096249SRichard Trieu *StartLoc = Expansion.getExpansionLocStart(); 1070c3096249SRichard Trieu return true; 1071402bb388SChandler Carruth } 10729dc9c206SChris Lattner 1073b1e71a7dSMatt Beaumont-Gay bool SourceManager::isMacroBodyExpansion(SourceLocation Loc) const { 1074b1e71a7dSMatt Beaumont-Gay if (!Loc.isMacroID()) return false; 1075b1e71a7dSMatt Beaumont-Gay 1076b1e71a7dSMatt Beaumont-Gay FileID FID = getFileID(Loc); 1077b1e71a7dSMatt Beaumont-Gay const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion(); 1078b1e71a7dSMatt Beaumont-Gay return Expansion.isMacroBodyExpansion(); 1079b1e71a7dSMatt Beaumont-Gay } 1080b1e71a7dSMatt Beaumont-Gay 1081065d720cSArgyrios Kyrtzidis bool SourceManager::isAtStartOfImmediateMacroExpansion(SourceLocation Loc, 1082065d720cSArgyrios Kyrtzidis SourceLocation *MacroBegin) const { 1083065d720cSArgyrios Kyrtzidis assert(Loc.isValid() && Loc.isMacroID() && "Expected a valid macro loc"); 1084065d720cSArgyrios Kyrtzidis 1085065d720cSArgyrios Kyrtzidis std::pair<FileID, unsigned> DecompLoc = getDecomposedLoc(Loc); 1086065d720cSArgyrios Kyrtzidis if (DecompLoc.second > 0) 1087065d720cSArgyrios Kyrtzidis return false; // Does not point at the start of expansion range. 1088065d720cSArgyrios Kyrtzidis 1089065d720cSArgyrios Kyrtzidis bool Invalid = false; 1090065d720cSArgyrios Kyrtzidis const SrcMgr::ExpansionInfo &ExpInfo = 1091065d720cSArgyrios Kyrtzidis getSLocEntry(DecompLoc.first, &Invalid).getExpansion(); 1092065d720cSArgyrios Kyrtzidis if (Invalid) 1093065d720cSArgyrios Kyrtzidis return false; 1094065d720cSArgyrios Kyrtzidis SourceLocation ExpLoc = ExpInfo.getExpansionLocStart(); 1095065d720cSArgyrios Kyrtzidis 1096065d720cSArgyrios Kyrtzidis if (ExpInfo.isMacroArgExpansion()) { 1097065d720cSArgyrios Kyrtzidis // For macro argument expansions, check if the previous FileID is part of 1098065d720cSArgyrios Kyrtzidis // the same argument expansion, in which case this Loc is not at the 1099065d720cSArgyrios Kyrtzidis // beginning of the expansion. 1100065d720cSArgyrios Kyrtzidis FileID PrevFID = getPreviousFileID(DecompLoc.first); 1101065d720cSArgyrios Kyrtzidis if (!PrevFID.isInvalid()) { 1102065d720cSArgyrios Kyrtzidis const SrcMgr::SLocEntry &PrevEntry = getSLocEntry(PrevFID, &Invalid); 1103065d720cSArgyrios Kyrtzidis if (Invalid) 1104065d720cSArgyrios Kyrtzidis return false; 1105065d720cSArgyrios Kyrtzidis if (PrevEntry.isExpansion() && 1106065d720cSArgyrios Kyrtzidis PrevEntry.getExpansion().getExpansionLocStart() == ExpLoc) 1107065d720cSArgyrios Kyrtzidis return false; 1108065d720cSArgyrios Kyrtzidis } 1109065d720cSArgyrios Kyrtzidis } 1110065d720cSArgyrios Kyrtzidis 1111065d720cSArgyrios Kyrtzidis if (MacroBegin) 1112065d720cSArgyrios Kyrtzidis *MacroBegin = ExpLoc; 1113065d720cSArgyrios Kyrtzidis return true; 1114065d720cSArgyrios Kyrtzidis } 1115065d720cSArgyrios Kyrtzidis 1116065d720cSArgyrios Kyrtzidis bool SourceManager::isAtEndOfImmediateMacroExpansion(SourceLocation Loc, 1117065d720cSArgyrios Kyrtzidis SourceLocation *MacroEnd) const { 1118065d720cSArgyrios Kyrtzidis assert(Loc.isValid() && Loc.isMacroID() && "Expected a valid macro loc"); 1119065d720cSArgyrios Kyrtzidis 1120065d720cSArgyrios Kyrtzidis FileID FID = getFileID(Loc); 1121065d720cSArgyrios Kyrtzidis SourceLocation NextLoc = Loc.getLocWithOffset(1); 1122065d720cSArgyrios Kyrtzidis if (isInFileID(NextLoc, FID)) 1123065d720cSArgyrios Kyrtzidis return false; // Does not point at the end of expansion range. 1124065d720cSArgyrios Kyrtzidis 1125065d720cSArgyrios Kyrtzidis bool Invalid = false; 1126065d720cSArgyrios Kyrtzidis const SrcMgr::ExpansionInfo &ExpInfo = 1127065d720cSArgyrios Kyrtzidis getSLocEntry(FID, &Invalid).getExpansion(); 1128065d720cSArgyrios Kyrtzidis if (Invalid) 1129065d720cSArgyrios Kyrtzidis return false; 1130065d720cSArgyrios Kyrtzidis 1131065d720cSArgyrios Kyrtzidis if (ExpInfo.isMacroArgExpansion()) { 1132065d720cSArgyrios Kyrtzidis // For macro argument expansions, check if the next FileID is part of the 1133065d720cSArgyrios Kyrtzidis // same argument expansion, in which case this Loc is not at the end of the 1134065d720cSArgyrios Kyrtzidis // expansion. 1135065d720cSArgyrios Kyrtzidis FileID NextFID = getNextFileID(FID); 1136065d720cSArgyrios Kyrtzidis if (!NextFID.isInvalid()) { 1137065d720cSArgyrios Kyrtzidis const SrcMgr::SLocEntry &NextEntry = getSLocEntry(NextFID, &Invalid); 1138065d720cSArgyrios Kyrtzidis if (Invalid) 1139065d720cSArgyrios Kyrtzidis return false; 1140065d720cSArgyrios Kyrtzidis if (NextEntry.isExpansion() && 1141065d720cSArgyrios Kyrtzidis NextEntry.getExpansion().getExpansionLocStart() == 1142065d720cSArgyrios Kyrtzidis ExpInfo.getExpansionLocStart()) 1143065d720cSArgyrios Kyrtzidis return false; 1144065d720cSArgyrios Kyrtzidis } 1145065d720cSArgyrios Kyrtzidis } 1146065d720cSArgyrios Kyrtzidis 1147065d720cSArgyrios Kyrtzidis if (MacroEnd) 1148065d720cSArgyrios Kyrtzidis *MacroEnd = ExpInfo.getExpansionLocEnd(); 1149065d720cSArgyrios Kyrtzidis return true; 1150065d720cSArgyrios Kyrtzidis } 1151065d720cSArgyrios Kyrtzidis 11524fa23625SChris Lattner //===----------------------------------------------------------------------===// 11534fa23625SChris Lattner // Queries about the code at a SourceLocation. 11544fa23625SChris Lattner //===----------------------------------------------------------------------===// 11557a51313dSChris Lattner 11567a51313dSChris Lattner /// getCharacterData - Return a pointer to the start of the specified location 11577a51313dSChris Lattner /// in the appropriate MemoryBuffer. 11587bda4b83SDouglas Gregor const char *SourceManager::getCharacterData(SourceLocation SL, 11597bda4b83SDouglas Gregor bool *Invalid) const { 11607a51313dSChris Lattner // Note that this is a hot function in the getSpelling() path, which is 11617a51313dSChris Lattner // heavily used by -E mode. 11624fa23625SChris Lattner std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(SL); 1163d32480d3SChris Lattner 116412c2af44STed Kremenek // Note that calling 'getBuffer()' may lazily page in a source file. 11657bda4b83SDouglas Gregor bool CharDataInvalid = false; 116649f754f4SDouglas Gregor const SLocEntry &Entry = getSLocEntry(LocInfo.first, &CharDataInvalid); 116749f754f4SDouglas Gregor if (CharDataInvalid || !Entry.isFile()) { 116849f754f4SDouglas Gregor if (Invalid) 116949f754f4SDouglas Gregor *Invalid = true; 117049f754f4SDouglas Gregor 117149f754f4SDouglas Gregor return "<<<<INVALID BUFFER>>>>"; 117249f754f4SDouglas Gregor } 1173d758f79eSDuncan P. N. Exon Smith llvm::Optional<llvm::MemoryBufferRef> Buffer = 117474a87834SDuncan P. N. Exon Smith Entry.getFile().getContentCache().getBufferOrNone(Diag, getFileManager(), 1175d758f79eSDuncan P. N. Exon Smith SourceLocation()); 11767bda4b83SDouglas Gregor if (Invalid) 1177d758f79eSDuncan P. N. Exon Smith *Invalid = !Buffer; 1178d758f79eSDuncan P. N. Exon Smith return Buffer ? Buffer->getBufferStart() + LocInfo.second 1179d758f79eSDuncan P. N. Exon Smith : "<<<<INVALID BUFFER>>>>"; 11807a51313dSChris Lattner } 11817a51313dSChris Lattner 11827a51313dSChris Lattner /// getColumnNumber - Return the column # for the specified file position. 1183e4ad4176SChris Lattner /// this is significantly cheaper to compute than the line number. 11847bda4b83SDouglas Gregor unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos, 11857bda4b83SDouglas Gregor bool *Invalid) const { 118654c1bcabSDuncan P. N. Exon Smith llvm::Optional<llvm::MemoryBufferRef> MemBuf = getBufferOrNone(FID); 11877bda4b83SDouglas Gregor if (Invalid) 118854c1bcabSDuncan P. N. Exon Smith *Invalid = !MemBuf; 11897bda4b83SDouglas Gregor 119054c1bcabSDuncan P. N. Exon Smith if (!MemBuf) 11917bda4b83SDouglas Gregor return 1; 11927a51313dSChris Lattner 11938d63d5b8SJordan Rose // It is okay to request a position just past the end of the buffer. 11948d63d5b8SJordan Rose if (FilePos > MemBuf->getBufferSize()) { 11956c8d29f7SArgyrios Kyrtzidis if (Invalid) 11968d63d5b8SJordan Rose *Invalid = true; 11976c8d29f7SArgyrios Kyrtzidis return 1; 11986c8d29f7SArgyrios Kyrtzidis } 11996c8d29f7SArgyrios Kyrtzidis 1200a0b99e45SChih-Hung Hsieh const char *Buf = MemBuf->getBufferStart(); 12015e79ee08SCraig Topper // See if we just calculated the line number for this FilePos and can use 12025e79ee08SCraig Topper // that to lookup the start of the line instead of searching for it. 1203*dbbc4f4eSDuncan P. N. Exon Smith if (LastLineNoFileIDQuery == FID && LastLineNoContentCache->SourceLineCache && 1204*dbbc4f4eSDuncan P. N. Exon Smith LastLineNoResult < LastLineNoContentCache->SourceLineCache.size()) { 1205*dbbc4f4eSDuncan P. N. Exon Smith const unsigned *SourceLineCache = 1206*dbbc4f4eSDuncan P. N. Exon Smith LastLineNoContentCache->SourceLineCache.begin(); 12075e79ee08SCraig Topper unsigned LineStart = SourceLineCache[LastLineNoResult - 1]; 12085e79ee08SCraig Topper unsigned LineEnd = SourceLineCache[LastLineNoResult]; 1209a0b99e45SChih-Hung Hsieh if (FilePos >= LineStart && FilePos < LineEnd) { 1210a0b99e45SChih-Hung Hsieh // LineEnd is the LineStart of the next line. 1211a0b99e45SChih-Hung Hsieh // A line ends with separator LF or CR+LF on Windows. 1212a0b99e45SChih-Hung Hsieh // FilePos might point to the last separator, 1213a0b99e45SChih-Hung Hsieh // but we need a column number at most 1 + the last column. 1214a0b99e45SChih-Hung Hsieh if (FilePos + 1 == LineEnd && FilePos > LineStart) { 1215a0b99e45SChih-Hung Hsieh if (Buf[FilePos - 1] == '\r' || Buf[FilePos - 1] == '\n') 1216a0b99e45SChih-Hung Hsieh --FilePos; 1217a0b99e45SChih-Hung Hsieh } 12185e79ee08SCraig Topper return FilePos - LineStart + 1; 12195e79ee08SCraig Topper } 1220a0b99e45SChih-Hung Hsieh } 12215e79ee08SCraig Topper 12227a51313dSChris Lattner unsigned LineStart = FilePos; 12237a51313dSChris Lattner while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r') 12247a51313dSChris Lattner --LineStart; 12257a51313dSChris Lattner return FilePos-LineStart+1; 12267a51313dSChris Lattner } 12277a51313dSChris Lattner 1228ea6d7f33SZhanyong Wan // isInvalid - Return the result of calling loc.isInvalid(), and 1229ea6d7f33SZhanyong Wan // if Invalid is not null, set its value to same. 123041e66291SRichard Smith template<typename LocType> 123141e66291SRichard Smith static bool isInvalid(LocType Loc, bool *Invalid) { 1232ea6d7f33SZhanyong Wan bool MyInvalid = Loc.isInvalid(); 1233ea6d7f33SZhanyong Wan if (Invalid) 1234ea6d7f33SZhanyong Wan *Invalid = MyInvalid; 1235ea6d7f33SZhanyong Wan return MyInvalid; 1236ea6d7f33SZhanyong Wan } 1237ea6d7f33SZhanyong Wan 12387bda4b83SDouglas Gregor unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc, 12397bda4b83SDouglas Gregor bool *Invalid) const { 1240ea6d7f33SZhanyong Wan if (isInvalid(Loc, Invalid)) return 0; 1241e4ad4176SChris Lattner std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc); 12427bda4b83SDouglas Gregor return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); 1243e4ad4176SChris Lattner } 1244e4ad4176SChris Lattner 124542f35f9cSChandler Carruth unsigned SourceManager::getExpansionColumnNumber(SourceLocation Loc, 12467bda4b83SDouglas Gregor bool *Invalid) const { 1247ea6d7f33SZhanyong Wan if (isInvalid(Loc, Invalid)) return 0; 1248c7ca5218SChandler Carruth std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); 12497bda4b83SDouglas Gregor return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); 1250e4ad4176SChris Lattner } 1251e4ad4176SChris Lattner 12521aef0c56SChandler Carruth unsigned SourceManager::getPresumedColumnNumber(SourceLocation Loc, 12531aef0c56SChandler Carruth bool *Invalid) const { 125441e66291SRichard Smith PresumedLoc PLoc = getPresumedLoc(Loc); 125541e66291SRichard Smith if (isInvalid(PLoc, Invalid)) return 0; 125641e66291SRichard Smith return PLoc.getColumn(); 12571aef0c56SChandler Carruth } 12581aef0c56SChandler Carruth 1259543036a4SBenjamin Kramer #ifdef __SSE2__ 1260543036a4SBenjamin Kramer #include <emmintrin.h> 1261543036a4SBenjamin Kramer #endif 1262543036a4SBenjamin Kramer 1263c3ce5840SChandler Carruth static LLVM_ATTRIBUTE_NOINLINE void 12649c902b55SDavid Blaikie ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI, 12657bda4b83SDouglas Gregor llvm::BumpPtrAllocator &Alloc, 1266fb24a3a4SChris Lattner const SourceManager &SM, bool &Invalid); 12679c902b55SDavid Blaikie static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI, 1268fb24a3a4SChris Lattner llvm::BumpPtrAllocator &Alloc, 1269fb24a3a4SChris Lattner const SourceManager &SM, bool &Invalid) { 127012c2af44STed Kremenek // Note that calling 'getBuffer()' may lazily page in the file. 1271d758f79eSDuncan P. N. Exon Smith llvm::Optional<llvm::MemoryBufferRef> Buffer = 1272d758f79eSDuncan P. N. Exon Smith FI->getBufferOrNone(Diag, SM.getFileManager(), SourceLocation()); 1273d758f79eSDuncan P. N. Exon Smith Invalid = !Buffer; 12747bda4b83SDouglas Gregor if (Invalid) 12757bda4b83SDouglas Gregor return; 12767a51313dSChris Lattner 1277*dbbc4f4eSDuncan P. N. Exon Smith FI->SourceLineCache = LineOffsetMapping::get(*Buffer, Alloc); 1278*dbbc4f4eSDuncan P. N. Exon Smith } 1279*dbbc4f4eSDuncan P. N. Exon Smith 1280*dbbc4f4eSDuncan P. N. Exon Smith LineOffsetMapping LineOffsetMapping::get(llvm::MemoryBufferRef Buffer, 1281*dbbc4f4eSDuncan P. N. Exon Smith llvm::BumpPtrAllocator &Alloc) { 12827a51313dSChris Lattner // Find the file offsets of all of the *physical* source lines. This does 12837a51313dSChris Lattner // not look at trigraphs, escaped newlines, or anything else tricky. 12840e62c1ccSChris Lattner SmallVector<unsigned, 256> LineOffsets; 12857a51313dSChris Lattner 12867a51313dSChris Lattner // Line #1 starts at char 0. 12877a51313dSChris Lattner LineOffsets.push_back(0); 12887a51313dSChris Lattner 1289*dbbc4f4eSDuncan P. N. Exon Smith const unsigned char *Buf = (const unsigned char *)Buffer.getBufferStart(); 1290*dbbc4f4eSDuncan P. N. Exon Smith const unsigned char *End = (const unsigned char *)Buffer.getBufferEnd(); 1291f28972faSJan Korous const std::size_t BufLen = End - Buf; 1292d906e731SFangrui Song unsigned I = 0; 1293f28972faSJan Korous while (I < BufLen) { 1294f28972faSJan Korous if (Buf[I] == '\n') { 1295f28972faSJan Korous LineOffsets.push_back(I + 1); 1296f28972faSJan Korous } else if (Buf[I] == '\r') { 1297d906e731SFangrui Song // If this is \r\n, skip both characters. 1298f28972faSJan Korous if (I + 1 < BufLen && Buf[I + 1] == '\n') 1299d906e731SFangrui Song ++I; 1300f28972faSJan Korous LineOffsets.push_back(I + 1); 13017a51313dSChris Lattner } 1302f28972faSJan Korous ++I; 13037a51313dSChris Lattner } 13047a51313dSChris Lattner 1305*dbbc4f4eSDuncan P. N. Exon Smith return LineOffsetMapping(LineOffsets, Alloc); 1306*dbbc4f4eSDuncan P. N. Exon Smith } 1307*dbbc4f4eSDuncan P. N. Exon Smith 1308*dbbc4f4eSDuncan P. N. Exon Smith LineOffsetMapping::LineOffsetMapping(ArrayRef<unsigned> LineOffsets, 1309*dbbc4f4eSDuncan P. N. Exon Smith llvm::BumpPtrAllocator &Alloc) 1310*dbbc4f4eSDuncan P. N. Exon Smith : Storage(Alloc.Allocate<unsigned>(LineOffsets.size() + 1)) { 1311*dbbc4f4eSDuncan P. N. Exon Smith Storage[0] = LineOffsets.size(); 1312*dbbc4f4eSDuncan P. N. Exon Smith std::copy(LineOffsets.begin(), LineOffsets.end(), Storage + 1); 13137a51313dSChris Lattner } 13147a51313dSChris Lattner 131553e384f6SChris Lattner /// getLineNumber - Given a SourceLocation, return the spelling line number 13167a51313dSChris Lattner /// for the position indicated. This requires building and caching a table of 13177a51313dSChris Lattner /// line offsets for the MemoryBuffer, so this is not cheap: use only when 13187a51313dSChris Lattner /// about to emit a diagnostic. 13197bda4b83SDouglas Gregor unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos, 13207bda4b83SDouglas Gregor bool *Invalid) const { 1321f15eac11SArgyrios Kyrtzidis if (FID.isInvalid()) { 1322f15eac11SArgyrios Kyrtzidis if (Invalid) 1323f15eac11SArgyrios Kyrtzidis *Invalid = true; 1324f15eac11SArgyrios Kyrtzidis return 1; 1325f15eac11SArgyrios Kyrtzidis } 1326f15eac11SArgyrios Kyrtzidis 13277a51313dSChris Lattner ContentCache *Content; 132888ea93e6SChris Lattner if (LastLineNoFileIDQuery == FID) 13297a51313dSChris Lattner Content = LastLineNoContentCache; 133049f754f4SDouglas Gregor else { 133149f754f4SDouglas Gregor bool MyInvalid = false; 133249f754f4SDouglas Gregor const SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); 133349f754f4SDouglas Gregor if (MyInvalid || !Entry.isFile()) { 133449f754f4SDouglas Gregor if (Invalid) 133549f754f4SDouglas Gregor *Invalid = true; 133649f754f4SDouglas Gregor return 1; 133749f754f4SDouglas Gregor } 133849f754f4SDouglas Gregor 133974a87834SDuncan P. N. Exon Smith Content = const_cast<ContentCache *>(&Entry.getFile().getContentCache()); 134049f754f4SDouglas Gregor } 13417a51313dSChris Lattner 13427a51313dSChris Lattner // If this is the first use of line information for this buffer, compute the 13437a51313dSChris Lattner /// SourceLineCache for it on demand. 1344f1186c5aSCraig Topper if (!Content->SourceLineCache) { 13457bda4b83SDouglas Gregor bool MyInvalid = false; 1346fb24a3a4SChris Lattner ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); 13477bda4b83SDouglas Gregor if (Invalid) 13487bda4b83SDouglas Gregor *Invalid = MyInvalid; 13497bda4b83SDouglas Gregor if (MyInvalid) 13507bda4b83SDouglas Gregor return 1; 13517bda4b83SDouglas Gregor } else if (Invalid) 13527bda4b83SDouglas Gregor *Invalid = false; 13537a51313dSChris Lattner 13547a51313dSChris Lattner // Okay, we know we have a line number table. Do a binary search to find the 13557a51313dSChris Lattner // line number that this character position lands on. 1356*dbbc4f4eSDuncan P. N. Exon Smith const unsigned *SourceLineCache = Content->SourceLineCache.begin(); 1357*dbbc4f4eSDuncan P. N. Exon Smith const unsigned *SourceLineCacheStart = SourceLineCache; 1358*dbbc4f4eSDuncan P. N. Exon Smith const unsigned *SourceLineCacheEnd = Content->SourceLineCache.end(); 13597a51313dSChris Lattner 136088ea93e6SChris Lattner unsigned QueriedFilePos = FilePos+1; 13617a51313dSChris Lattner 136270f924dfSDaniel Dunbar // FIXME: I would like to be convinced that this code is worth being as 136370f924dfSDaniel Dunbar // complicated as it is, binary search isn't that slow. 136470f924dfSDaniel Dunbar // 136570f924dfSDaniel Dunbar // If it is worth being optimized, then in my opinion it could be more 136670f924dfSDaniel Dunbar // performant, simpler, and more obviously correct by just "galloping" outward 136770f924dfSDaniel Dunbar // from the queried file position. In fact, this could be incorporated into a 136870f924dfSDaniel Dunbar // generic algorithm such as lower_bound_with_hint. 136970f924dfSDaniel Dunbar // 137070f924dfSDaniel Dunbar // If someone gives me a test case where this matters, and I will do it! - DWD 137170f924dfSDaniel Dunbar 13727a51313dSChris Lattner // If the previous query was to the same file, we know both the file pos from 13737a51313dSChris Lattner // that query and the line number returned. This allows us to narrow the 13747a51313dSChris Lattner // search space from the entire file to something near the match. 137588ea93e6SChris Lattner if (LastLineNoFileIDQuery == FID) { 13767a51313dSChris Lattner if (QueriedFilePos >= LastLineNoFilePos) { 137770f924dfSDaniel Dunbar // FIXME: Potential overflow? 13787a51313dSChris Lattner SourceLineCache = SourceLineCache+LastLineNoResult-1; 13797a51313dSChris Lattner 13807a51313dSChris Lattner // The query is likely to be nearby the previous one. Here we check to 13817a51313dSChris Lattner // see if it is within 5, 10 or 20 lines. It can be far away in cases 13827a51313dSChris Lattner // where big comment blocks and vertical whitespace eat up lines but 13837a51313dSChris Lattner // contribute no tokens. 13847a51313dSChris Lattner if (SourceLineCache+5 < SourceLineCacheEnd) { 13857a51313dSChris Lattner if (SourceLineCache[5] > QueriedFilePos) 13867a51313dSChris Lattner SourceLineCacheEnd = SourceLineCache+5; 13877a51313dSChris Lattner else if (SourceLineCache+10 < SourceLineCacheEnd) { 13887a51313dSChris Lattner if (SourceLineCache[10] > QueriedFilePos) 13897a51313dSChris Lattner SourceLineCacheEnd = SourceLineCache+10; 13907a51313dSChris Lattner else if (SourceLineCache+20 < SourceLineCacheEnd) { 13917a51313dSChris Lattner if (SourceLineCache[20] > QueriedFilePos) 13927a51313dSChris Lattner SourceLineCacheEnd = SourceLineCache+20; 13937a51313dSChris Lattner } 13947a51313dSChris Lattner } 13957a51313dSChris Lattner } 13967a51313dSChris Lattner } else { 1397*dbbc4f4eSDuncan P. N. Exon Smith if (LastLineNoResult < Content->SourceLineCache.size()) 13987a51313dSChris Lattner SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1; 13997a51313dSChris Lattner } 14007a51313dSChris Lattner } 14017a51313dSChris Lattner 1402*dbbc4f4eSDuncan P. N. Exon Smith const unsigned *Pos = 1403*dbbc4f4eSDuncan P. N. Exon Smith std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos); 14047a51313dSChris Lattner unsigned LineNo = Pos-SourceLineCacheStart; 14057a51313dSChris Lattner 140688ea93e6SChris Lattner LastLineNoFileIDQuery = FID; 14077a51313dSChris Lattner LastLineNoContentCache = Content; 14087a51313dSChris Lattner LastLineNoFilePos = QueriedFilePos; 14097a51313dSChris Lattner LastLineNoResult = LineNo; 14107a51313dSChris Lattner return LineNo; 14117a51313dSChris Lattner } 14127a51313dSChris Lattner 14131aef0c56SChandler Carruth unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc, 14141aef0c56SChandler Carruth bool *Invalid) const { 14151aef0c56SChandler Carruth if (isInvalid(Loc, Invalid)) return 0; 14161aef0c56SChandler Carruth std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc); 14171aef0c56SChandler Carruth return getLineNumber(LocInfo.first, LocInfo.second); 14181aef0c56SChandler Carruth } 1419d48db211SChandler Carruth unsigned SourceManager::getExpansionLineNumber(SourceLocation Loc, 14207bda4b83SDouglas Gregor bool *Invalid) const { 1421ea6d7f33SZhanyong Wan if (isInvalid(Loc, Invalid)) return 0; 1422c7ca5218SChandler Carruth std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); 142388ea93e6SChris Lattner return getLineNumber(LocInfo.first, LocInfo.second); 142488ea93e6SChris Lattner } 14251aef0c56SChandler Carruth unsigned SourceManager::getPresumedLineNumber(SourceLocation Loc, 14267bda4b83SDouglas Gregor bool *Invalid) const { 14279c52767fSRichard Smith PresumedLoc PLoc = getPresumedLoc(Loc); 14289c52767fSRichard Smith if (isInvalid(PLoc, Invalid)) return 0; 14299c52767fSRichard Smith return PLoc.getLine(); 143088ea93e6SChris Lattner } 143188ea93e6SChris Lattner 143295d9c5e7SChris Lattner /// getFileCharacteristic - return the file characteristic of the specified 143395d9c5e7SChris Lattner /// source location, indicating whether this is a normal file, a system 143495d9c5e7SChris Lattner /// header, or an "implicit extern C" system header. 143595d9c5e7SChris Lattner /// 143695d9c5e7SChris Lattner /// This state can be modified with flags on GNU linemarker directives like: 143795d9c5e7SChris Lattner /// # 4 "foo.h" 3 143895d9c5e7SChris Lattner /// which changes all source locations in the current file after that to be 143995d9c5e7SChris Lattner /// considered to be from a system header. 144095d9c5e7SChris Lattner SrcMgr::CharacteristicKind 144195d9c5e7SChris Lattner SourceManager::getFileCharacteristic(SourceLocation Loc) const { 14428b563665SYaron Keren assert(Loc.isValid() && "Can't get file characteristic of invalid loc!"); 1443c7ca5218SChandler Carruth std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); 1444b6c6daa9SDuncan P. N. Exon Smith const SLocEntry *SEntry = getSLocEntryForFile(LocInfo.first); 1445b6c6daa9SDuncan P. N. Exon Smith if (!SEntry) 144649f754f4SDouglas Gregor return C_User; 144749f754f4SDouglas Gregor 1448b6c6daa9SDuncan P. N. Exon Smith const SrcMgr::FileInfo &FI = SEntry->getFile(); 144995d9c5e7SChris Lattner 145095d9c5e7SChris Lattner // If there are no #line directives in this file, just return the whole-file 145195d9c5e7SChris Lattner // state. 145295d9c5e7SChris Lattner if (!FI.hasLineDirectives()) 145395d9c5e7SChris Lattner return FI.getFileCharacteristic(); 145495d9c5e7SChris Lattner 145595d9c5e7SChris Lattner assert(LineTable && "Can't have linetable entries without a LineTable!"); 145695d9c5e7SChris Lattner // See if there is a #line directive before the location. 145795d9c5e7SChris Lattner const LineEntry *Entry = 145802c2dbf4SDouglas Gregor LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second); 145995d9c5e7SChris Lattner 146095d9c5e7SChris Lattner // If this is before the first line marker, use the file characteristic. 146195d9c5e7SChris Lattner if (!Entry) 146295d9c5e7SChris Lattner return FI.getFileCharacteristic(); 146395d9c5e7SChris Lattner 146495d9c5e7SChris Lattner return Entry->FileKind; 146595d9c5e7SChris Lattner } 146695d9c5e7SChris Lattner 1467a6f037ceSChris Lattner /// Return the filename or buffer identifier of the buffer the location is in. 146887a2acf1SJames Dennett /// Note that this name does not respect \#line directives. Use getPresumedLoc 1469a6f037ceSChris Lattner /// for normal clients. 147099d1b295SMehdi Amini StringRef SourceManager::getBufferName(SourceLocation Loc, 14717bda4b83SDouglas Gregor bool *Invalid) const { 1472ea6d7f33SZhanyong Wan if (isInvalid(Loc, Invalid)) return "<invalid loc>"; 1473a6f037ceSChris Lattner 147454c1bcabSDuncan P. N. Exon Smith auto B = getBufferOrNone(getFileID(Loc)); 147554c1bcabSDuncan P. N. Exon Smith if (Invalid) 147654c1bcabSDuncan P. N. Exon Smith *Invalid = !B; 147754c1bcabSDuncan P. N. Exon Smith return B ? B->getBufferIdentifier() : "<invalid buffer>"; 1478a6f037ceSChris Lattner } 1479a6f037ceSChris Lattner 1480f1ca7d3eSChris Lattner /// getPresumedLoc - This method returns the "presumed" location of a 148187a2acf1SJames Dennett /// SourceLocation specifies. A "presumed location" can be modified by \#line 1482f1ca7d3eSChris Lattner /// or GNU line marker directives. This provides a view on the data that a 1483f1ca7d3eSChris Lattner /// user should see in diagnostics, for example. 1484f1ca7d3eSChris Lattner /// 148564ee782eSChandler Carruth /// Note that a presumed location is always given as the expansion point of an 148664ee782eSChandler Carruth /// expansion location, not at the spelling location. 14870b50cb79SRichard Smith PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc, 14880b50cb79SRichard Smith bool UseLineDirectives) const { 1489f1ca7d3eSChris Lattner if (Loc.isInvalid()) return PresumedLoc(); 14904fa23625SChris Lattner 149164ee782eSChandler Carruth // Presumed locations are always for expansion points. 1492c7ca5218SChandler Carruth std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); 1493f1ca7d3eSChris Lattner 149449f754f4SDouglas Gregor bool Invalid = false; 149549f754f4SDouglas Gregor const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); 149649f754f4SDouglas Gregor if (Invalid || !Entry.isFile()) 149749f754f4SDouglas Gregor return PresumedLoc(); 149849f754f4SDouglas Gregor 149949f754f4SDouglas Gregor const SrcMgr::FileInfo &FI = Entry.getFile(); 150074a87834SDuncan P. N. Exon Smith const SrcMgr::ContentCache *C = &FI.getContentCache(); 15014fa23625SChris Lattner 1502d4293922SChris Lattner // To get the source name, first consult the FileEntry (if one exists) 1503d4293922SChris Lattner // before the MemBuffer as this will avoid unnecessarily paging in the 1504d4293922SChris Lattner // MemBuffer. 1505047e65dbSAlexandre Ganea FileID FID = LocInfo.first; 150699d1b295SMehdi Amini StringRef Filename; 150711e6f0a6SArgyrios Kyrtzidis if (C->OrigEntry) 150811e6f0a6SArgyrios Kyrtzidis Filename = C->OrigEntry->getName(); 1509d758f79eSDuncan P. N. Exon Smith else if (auto Buffer = C->getBufferOrNone(Diag, getFileManager())) 1510d758f79eSDuncan P. N. Exon Smith Filename = Buffer->getBufferIdentifier(); 151149f754f4SDouglas Gregor 151275f26d6cSDouglas Gregor unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid); 151375f26d6cSDouglas Gregor if (Invalid) 151475f26d6cSDouglas Gregor return PresumedLoc(); 151575f26d6cSDouglas Gregor unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second, &Invalid); 151675f26d6cSDouglas Gregor if (Invalid) 151775f26d6cSDouglas Gregor return PresumedLoc(); 151875f26d6cSDouglas Gregor 1519d4293922SChris Lattner SourceLocation IncludeLoc = FI.getIncludeLoc(); 1520f1ca7d3eSChris Lattner 1521d4293922SChris Lattner // If we have #line directives in this file, update and overwrite the physical 1522d4293922SChris Lattner // location info if appropriate. 15230b50cb79SRichard Smith if (UseLineDirectives && FI.hasLineDirectives()) { 1524d4293922SChris Lattner assert(LineTable && "Can't have linetable entries without a LineTable!"); 1525d4293922SChris Lattner // See if there is a #line directive before this. If so, get it. 1526d4293922SChris Lattner if (const LineEntry *Entry = 152702c2dbf4SDouglas Gregor LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second)) { 1528c1219ff7SChris Lattner // If the LineEntry indicates a filename, use it. 1529047e65dbSAlexandre Ganea if (Entry->FilenameID != -1) { 1530d4293922SChris Lattner Filename = LineTable->getFilename(Entry->FilenameID); 1531047e65dbSAlexandre Ganea // The contents of files referenced by #line are not in the 1532047e65dbSAlexandre Ganea // SourceManager 1533047e65dbSAlexandre Ganea FID = FileID::get(0); 1534047e65dbSAlexandre Ganea } 1535c1219ff7SChris Lattner 1536c1219ff7SChris Lattner // Use the line number specified by the LineEntry. This line number may 1537c1219ff7SChris Lattner // be multiple lines down from the line entry. Add the difference in 1538c1219ff7SChris Lattner // physical line numbers from the query point and the line marker to the 1539c1219ff7SChris Lattner // total. 1540c1219ff7SChris Lattner unsigned MarkerLineNo = getLineNumber(LocInfo.first, Entry->FileOffset); 1541c1219ff7SChris Lattner LineNo = Entry->LineNo + (LineNo-MarkerLineNo-1); 1542c1219ff7SChris Lattner 154320c50ba2SChris Lattner // Note that column numbers are not molested by line markers. 15441c967784SChris Lattner 15451c967784SChris Lattner // Handle virtual #include manipulation. 15461c967784SChris Lattner if (Entry->IncludeOffset) { 15471c967784SChris Lattner IncludeLoc = getLocForStartOfFile(LocInfo.first); 1548e6e67deeSArgyrios Kyrtzidis IncludeLoc = IncludeLoc.getLocWithOffset(Entry->IncludeOffset); 15491c967784SChris Lattner } 1550d4293922SChris Lattner } 1551d4293922SChris Lattner } 1552d4293922SChris Lattner 1553047e65dbSAlexandre Ganea return PresumedLoc(Filename.data(), FID, LineNo, ColNo, IncludeLoc); 15544fa23625SChris Lattner } 15554fa23625SChris Lattner 15569fc8faf9SAdrian Prantl /// Returns whether the PresumedLoc for a given SourceLocation is 1557e7800df4SBenjamin Kramer /// in the main file. 1558e7800df4SBenjamin Kramer /// 1559e7800df4SBenjamin Kramer /// This computes the "presumed" location for a SourceLocation, then checks 1560e7800df4SBenjamin Kramer /// whether it came from a file other than the main file. This is different 1561e7800df4SBenjamin Kramer /// from isWrittenInMainFile() because it takes line marker directives into 1562e7800df4SBenjamin Kramer /// account. 1563e7800df4SBenjamin Kramer bool SourceManager::isInMainFile(SourceLocation Loc) const { 1564e7800df4SBenjamin Kramer if (Loc.isInvalid()) return false; 1565e7800df4SBenjamin Kramer 1566e7800df4SBenjamin Kramer // Presumed locations are always for expansion points. 1567e7800df4SBenjamin Kramer std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); 1568e7800df4SBenjamin Kramer 1569b6c6daa9SDuncan P. N. Exon Smith const SLocEntry *Entry = getSLocEntryForFile(LocInfo.first); 1570b6c6daa9SDuncan P. N. Exon Smith if (!Entry) 1571e7800df4SBenjamin Kramer return false; 1572e7800df4SBenjamin Kramer 1573b6c6daa9SDuncan P. N. Exon Smith const SrcMgr::FileInfo &FI = Entry->getFile(); 1574e7800df4SBenjamin Kramer 1575e7800df4SBenjamin Kramer // Check if there is a line directive for this location. 1576e7800df4SBenjamin Kramer if (FI.hasLineDirectives()) 1577e7800df4SBenjamin Kramer if (const LineEntry *Entry = 1578e7800df4SBenjamin Kramer LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second)) 1579e7800df4SBenjamin Kramer if (Entry->IncludeOffset) 1580e7800df4SBenjamin Kramer return false; 1581e7800df4SBenjamin Kramer 1582e7800df4SBenjamin Kramer return FI.getIncludeLoc().isInvalid(); 1583e7800df4SBenjamin Kramer } 1584e7800df4SBenjamin Kramer 15859fc8faf9SAdrian Prantl /// The size of the SLocEntry that \p FID represents. 1586296374b5SArgyrios Kyrtzidis unsigned SourceManager::getFileIDSize(FileID FID) const { 1587296374b5SArgyrios Kyrtzidis bool Invalid = false; 1588296374b5SArgyrios Kyrtzidis const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); 1589296374b5SArgyrios Kyrtzidis if (Invalid) 1590296374b5SArgyrios Kyrtzidis return 0; 1591296374b5SArgyrios Kyrtzidis 1592296374b5SArgyrios Kyrtzidis int ID = FID.ID; 1593296374b5SArgyrios Kyrtzidis unsigned NextOffset; 1594296374b5SArgyrios Kyrtzidis if ((ID > 0 && unsigned(ID+1) == local_sloc_entry_size())) 1595296374b5SArgyrios Kyrtzidis NextOffset = getNextLocalOffset(); 1596296374b5SArgyrios Kyrtzidis else if (ID+1 == -1) 1597296374b5SArgyrios Kyrtzidis NextOffset = MaxLoadedOffset; 1598296374b5SArgyrios Kyrtzidis else 1599296374b5SArgyrios Kyrtzidis NextOffset = getSLocEntry(FileID::get(ID+1)).getOffset(); 1600296374b5SArgyrios Kyrtzidis 1601296374b5SArgyrios Kyrtzidis return NextOffset - Entry.getOffset() - 1; 1602296374b5SArgyrios Kyrtzidis } 1603296374b5SArgyrios Kyrtzidis 16044fa23625SChris Lattner //===----------------------------------------------------------------------===// 16054fa23625SChris Lattner // Other miscellaneous methods. 16064fa23625SChris Lattner //===----------------------------------------------------------------------===// 16074fa23625SChris Lattner 16089fc8faf9SAdrian Prantl /// Get the source location for the given file:line:col triplet. 160988f663c0SArgyrios Kyrtzidis /// 161088f663c0SArgyrios Kyrtzidis /// If the source file is included multiple times, the source location will 1611925296b4SDouglas Gregor /// be based upon an arbitrary inclusion. 161292a47bd9SArgyrios Kyrtzidis SourceLocation SourceManager::translateFileLineCol(const FileEntry *SourceFile, 16137c06d866SArgyrios Kyrtzidis unsigned Line, 16147c06d866SArgyrios Kyrtzidis unsigned Col) const { 161588f663c0SArgyrios Kyrtzidis assert(SourceFile && "Null source file!"); 161688f663c0SArgyrios Kyrtzidis assert(Line && Col && "Line and column should start from 1!"); 161788f663c0SArgyrios Kyrtzidis 161804a6e5f8SArgyrios Kyrtzidis FileID FirstFID = translateFile(SourceFile); 161904a6e5f8SArgyrios Kyrtzidis return translateLineCol(FirstFID, Line, Col); 162004a6e5f8SArgyrios Kyrtzidis } 162104a6e5f8SArgyrios Kyrtzidis 16229fc8faf9SAdrian Prantl /// Get the FileID for the given file. 162304a6e5f8SArgyrios Kyrtzidis /// 162404a6e5f8SArgyrios Kyrtzidis /// If the source file is included multiple times, the FileID will be the 162504a6e5f8SArgyrios Kyrtzidis /// first inclusion. 162604a6e5f8SArgyrios Kyrtzidis FileID SourceManager::translateFile(const FileEntry *SourceFile) const { 162704a6e5f8SArgyrios Kyrtzidis assert(SourceFile && "Null source file!"); 162804a6e5f8SArgyrios Kyrtzidis 1629e664276bSDouglas Gregor // First, check the main file ID, since it is common to look for a 1630e664276bSDouglas Gregor // location in the main file. 16318b563665SYaron Keren if (MainFileID.isValid()) { 163249f754f4SDouglas Gregor bool Invalid = false; 163349f754f4SDouglas Gregor const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid); 163449f754f4SDouglas Gregor if (Invalid) 163504a6e5f8SArgyrios Kyrtzidis return FileID(); 163649f754f4SDouglas Gregor 1637e664276bSDouglas Gregor if (MainSLoc.isFile()) { 163874a87834SDuncan P. N. Exon Smith if (MainSLoc.getFile().getContentCache().OrigEntry == SourceFile) 163906abd696SAlex Lorenz return MainFileID; 1640d766be68SDouglas Gregor } 1641d766be68SDouglas Gregor } 1642e664276bSDouglas Gregor 1643e664276bSDouglas Gregor // The location we're looking for isn't in the main file; look 1644925296b4SDouglas Gregor // through all of the local source locations. 1645925296b4SDouglas Gregor for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) { 16468cce7af0SNick Desaulniers const SLocEntry &SLoc = getLocalSLocEntry(I); 164774a87834SDuncan P. N. Exon Smith if (SLoc.isFile() && 164874a87834SDuncan P. N. Exon Smith SLoc.getFile().getContentCache().OrigEntry == SourceFile) 164906abd696SAlex Lorenz return FileID::get(I); 1650e664276bSDouglas Gregor } 165106abd696SAlex Lorenz 1652925296b4SDouglas Gregor // If that still didn't help, try the modules. 1653925296b4SDouglas Gregor for (unsigned I = 0, N = loaded_sloc_entry_size(); I != N; ++I) { 1654925296b4SDouglas Gregor const SLocEntry &SLoc = getLoadedSLocEntry(I); 165574a87834SDuncan P. N. Exon Smith if (SLoc.isFile() && 165674a87834SDuncan P. N. Exon Smith SLoc.getFile().getContentCache().OrigEntry == SourceFile) 165706abd696SAlex Lorenz return FileID::get(-int(I) - 2); 1658e664276bSDouglas Gregor } 1659e664276bSDouglas Gregor 166004a6e5f8SArgyrios Kyrtzidis return FileID(); 1661532c5196SArgyrios Kyrtzidis } 1662532c5196SArgyrios Kyrtzidis 16639fc8faf9SAdrian Prantl /// Get the source location in \arg FID for the given line:col. 1664532c5196SArgyrios Kyrtzidis /// Returns null location if \arg FID is not a file SLocEntry. 1665532c5196SArgyrios Kyrtzidis SourceLocation SourceManager::translateLineCol(FileID FID, 16667c06d866SArgyrios Kyrtzidis unsigned Line, 16677c06d866SArgyrios Kyrtzidis unsigned Col) const { 1668ef1cf830SAaron Ballman // Lines are used as a one-based index into a zero-based array. This assert 1669ef1cf830SAaron Ballman // checks for possible buffer underruns. 1670fe2c0ff9SGabor Horvath assert(Line && Col && "Line and column should start from 1!"); 1671ef1cf830SAaron Ballman 1672532c5196SArgyrios Kyrtzidis if (FID.isInvalid()) 1673532c5196SArgyrios Kyrtzidis return SourceLocation(); 1674532c5196SArgyrios Kyrtzidis 1675532c5196SArgyrios Kyrtzidis bool Invalid = false; 1676532c5196SArgyrios Kyrtzidis const SLocEntry &Entry = getSLocEntry(FID, &Invalid); 1677532c5196SArgyrios Kyrtzidis if (Invalid) 1678532c5196SArgyrios Kyrtzidis return SourceLocation(); 1679532c5196SArgyrios Kyrtzidis 1680532c5196SArgyrios Kyrtzidis if (!Entry.isFile()) 168188f663c0SArgyrios Kyrtzidis return SourceLocation(); 1682e664276bSDouglas Gregor 16837c2b28a1SArgyrios Kyrtzidis SourceLocation FileLoc = SourceLocation::getFileLoc(Entry.getOffset()); 16847c2b28a1SArgyrios Kyrtzidis 1685e664276bSDouglas Gregor if (Line == 1 && Col == 1) 16867c2b28a1SArgyrios Kyrtzidis return FileLoc; 1687e664276bSDouglas Gregor 168874a87834SDuncan P. N. Exon Smith ContentCache *Content = 168974a87834SDuncan P. N. Exon Smith const_cast<ContentCache *>(&Entry.getFile().getContentCache()); 169088f663c0SArgyrios Kyrtzidis 169188f663c0SArgyrios Kyrtzidis // If this is the first use of line information for this buffer, compute the 1692925296b4SDouglas Gregor // SourceLineCache for it on demand. 1693f1186c5aSCraig Topper if (!Content->SourceLineCache) { 16947bda4b83SDouglas Gregor bool MyInvalid = false; 1695fb24a3a4SChris Lattner ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); 16967bda4b83SDouglas Gregor if (MyInvalid) 16977bda4b83SDouglas Gregor return SourceLocation(); 16987bda4b83SDouglas Gregor } 169988f663c0SArgyrios Kyrtzidis 1700d758f79eSDuncan P. N. Exon Smith llvm::Optional<llvm::MemoryBufferRef> Buffer = 1701d758f79eSDuncan P. N. Exon Smith Content->getBufferOrNone(Diag, getFileManager()); 1702d758f79eSDuncan P. N. Exon Smith if (!Buffer) 1703d758f79eSDuncan P. N. Exon Smith return SourceLocation(); 1704d758f79eSDuncan P. N. Exon Smith 1705*dbbc4f4eSDuncan P. N. Exon Smith if (Line > Content->SourceLineCache.size()) { 1706d758f79eSDuncan P. N. Exon Smith unsigned Size = Buffer->getBufferSize(); 1707b8b9f28eSDouglas Gregor if (Size > 0) 1708b8b9f28eSDouglas Gregor --Size; 17097c2b28a1SArgyrios Kyrtzidis return FileLoc.getLocWithOffset(Size); 1710b8b9f28eSDouglas Gregor } 1711b8b9f28eSDouglas Gregor 1712b8b9f28eSDouglas Gregor unsigned FilePos = Content->SourceLineCache[Line - 1]; 17132a8bc152SDylan Noblesmith const char *Buf = Buffer->getBufferStart() + FilePos; 17142a8bc152SDylan Noblesmith unsigned BufLength = Buffer->getBufferSize() - FilePos; 17157c2b28a1SArgyrios Kyrtzidis if (BufLength == 0) 17167c2b28a1SArgyrios Kyrtzidis return FileLoc.getLocWithOffset(FilePos); 17177c2b28a1SArgyrios Kyrtzidis 1718b8b9f28eSDouglas Gregor unsigned i = 0; 1719b8b9f28eSDouglas Gregor 1720b8b9f28eSDouglas Gregor // Check that the given column is valid. 1721b8b9f28eSDouglas Gregor while (i < BufLength-1 && i < Col-1 && Buf[i] != '\n' && Buf[i] != '\r') 1722b8b9f28eSDouglas Gregor ++i; 17237c2b28a1SArgyrios Kyrtzidis return FileLoc.getLocWithOffset(FilePos + i); 172488f663c0SArgyrios Kyrtzidis } 172588f663c0SArgyrios Kyrtzidis 17269fc8faf9SAdrian Prantl /// Compute a map of macro argument chunks to their expanded source 172761ef3db2SArgyrios Kyrtzidis /// location. Chunks that are not part of a macro argument will map to an 172861ef3db2SArgyrios Kyrtzidis /// invalid source location. e.g. if a file contains one macro argument at 172961ef3db2SArgyrios Kyrtzidis /// offset 100 with length 10, this is how the map will be formed: 173061ef3db2SArgyrios Kyrtzidis /// 0 -> SourceLocation() 173161ef3db2SArgyrios Kyrtzidis /// 100 -> Expanded macro arg location 173261ef3db2SArgyrios Kyrtzidis /// 110 -> SourceLocation() 1733d2c6a6d1SVedant Kumar void SourceManager::computeMacroArgsCache(MacroArgsMap &MacroArgsCache, 17347c06d866SArgyrios Kyrtzidis FileID FID) const { 17358b563665SYaron Keren assert(FID.isValid()); 173661ef3db2SArgyrios Kyrtzidis 173761ef3db2SArgyrios Kyrtzidis // Initially no macro argument chunk is present. 173861ef3db2SArgyrios Kyrtzidis MacroArgsCache.insert(std::make_pair(0, SourceLocation())); 173961ef3db2SArgyrios Kyrtzidis 174061ef3db2SArgyrios Kyrtzidis int ID = FID.ID; 1741918e0ca7SEugene Zelenko while (true) { 174261ef3db2SArgyrios Kyrtzidis ++ID; 174361ef3db2SArgyrios Kyrtzidis // Stop if there are no more FileIDs to check. 174461ef3db2SArgyrios Kyrtzidis if (ID > 0) { 174561ef3db2SArgyrios Kyrtzidis if (unsigned(ID) >= local_sloc_entry_size()) 174661ef3db2SArgyrios Kyrtzidis return; 174761ef3db2SArgyrios Kyrtzidis } else if (ID == -1) { 174861ef3db2SArgyrios Kyrtzidis return; 174961ef3db2SArgyrios Kyrtzidis } 175061ef3db2SArgyrios Kyrtzidis 1751fe68302fSArgyrios Kyrtzidis bool Invalid = false; 1752fe68302fSArgyrios Kyrtzidis const SrcMgr::SLocEntry &Entry = getSLocEntryByID(ID, &Invalid); 1753fe68302fSArgyrios Kyrtzidis if (Invalid) 1754fe68302fSArgyrios Kyrtzidis return; 175561ef3db2SArgyrios Kyrtzidis if (Entry.isFile()) { 17568277a513SJan Korous auto& File = Entry.getFile(); 1757e7870223SJan Korous if (File.getFileCharacteristic() == C_User_ModuleMap || 1758e7870223SJan Korous File.getFileCharacteristic() == C_System_ModuleMap) 1759e7870223SJan Korous continue; 1760e7870223SJan Korous 1761e7870223SJan Korous SourceLocation IncludeLoc = File.getIncludeLoc(); 1762411a254aSKadir Cetinkaya bool IncludedInFID = 1763411a254aSKadir Cetinkaya (IncludeLoc.isValid() && isInFileID(IncludeLoc, FID)) || 1764411a254aSKadir Cetinkaya // Predefined header doesn't have a valid include location in main 1765411a254aSKadir Cetinkaya // file, but any files created by it should still be skipped when 1766411a254aSKadir Cetinkaya // computing macro args expanded in the main file. 1767411a254aSKadir Cetinkaya (FID == MainFileID && Entry.getFile().Filename == "<built-in>"); 1768411a254aSKadir Cetinkaya if (IncludedInFID) { 1769411a254aSKadir Cetinkaya // Skip the files/macros of the #include'd file, we only care about 1770411a254aSKadir Cetinkaya // macros that lexed macro arguments from our file. 177161ef3db2SArgyrios Kyrtzidis if (Entry.getFile().NumCreatedFIDs) 177261ef3db2SArgyrios Kyrtzidis ID += Entry.getFile().NumCreatedFIDs - 1 /*because of next ++ID*/; 177361ef3db2SArgyrios Kyrtzidis continue; 1774411a254aSKadir Cetinkaya } else if (IncludeLoc.isValid()) { 1775411a254aSKadir Cetinkaya // If file was included but not from FID, there is no more files/macros 1776411a254aSKadir Cetinkaya // that may be "contained" in this file. 1777411a254aSKadir Cetinkaya return; 1778411a254aSKadir Cetinkaya } 1779411a254aSKadir Cetinkaya continue; 178061ef3db2SArgyrios Kyrtzidis } 178161ef3db2SArgyrios Kyrtzidis 1782e841c901SArgyrios Kyrtzidis const ExpansionInfo &ExpInfo = Entry.getExpansion(); 1783e841c901SArgyrios Kyrtzidis 1784e841c901SArgyrios Kyrtzidis if (ExpInfo.getExpansionLocStart().isFileID()) { 1785e841c901SArgyrios Kyrtzidis if (!isInFileID(ExpInfo.getExpansionLocStart(), FID)) 1786e841c901SArgyrios Kyrtzidis return; // No more files/macros that may be "contained" in this file. 1787e841c901SArgyrios Kyrtzidis } 1788e841c901SArgyrios Kyrtzidis 1789e841c901SArgyrios Kyrtzidis if (!ExpInfo.isMacroArgExpansion()) 179061ef3db2SArgyrios Kyrtzidis continue; 179161ef3db2SArgyrios Kyrtzidis 179273ccdb9cSArgyrios Kyrtzidis associateFileChunkWithMacroArgExp(MacroArgsCache, FID, 179373ccdb9cSArgyrios Kyrtzidis ExpInfo.getSpellingLoc(), 179473ccdb9cSArgyrios Kyrtzidis SourceLocation::getMacroLoc(Entry.getOffset()), 179573ccdb9cSArgyrios Kyrtzidis getFileIDSize(FileID::get(ID))); 1796e841c901SArgyrios Kyrtzidis } 179773ccdb9cSArgyrios Kyrtzidis } 179873ccdb9cSArgyrios Kyrtzidis 179973ccdb9cSArgyrios Kyrtzidis void SourceManager::associateFileChunkWithMacroArgExp( 180073ccdb9cSArgyrios Kyrtzidis MacroArgsMap &MacroArgsCache, 180173ccdb9cSArgyrios Kyrtzidis FileID FID, 180273ccdb9cSArgyrios Kyrtzidis SourceLocation SpellLoc, 180373ccdb9cSArgyrios Kyrtzidis SourceLocation ExpansionLoc, 180473ccdb9cSArgyrios Kyrtzidis unsigned ExpansionLength) const { 180573ccdb9cSArgyrios Kyrtzidis if (!SpellLoc.isFileID()) { 180673ccdb9cSArgyrios Kyrtzidis unsigned SpellBeginOffs = SpellLoc.getOffset(); 180773ccdb9cSArgyrios Kyrtzidis unsigned SpellEndOffs = SpellBeginOffs + ExpansionLength; 180873ccdb9cSArgyrios Kyrtzidis 180973ccdb9cSArgyrios Kyrtzidis // The spelling range for this macro argument expansion can span multiple 181073ccdb9cSArgyrios Kyrtzidis // consecutive FileID entries. Go through each entry contained in the 181173ccdb9cSArgyrios Kyrtzidis // spelling range and if one is itself a macro argument expansion, recurse 181273ccdb9cSArgyrios Kyrtzidis // and associate the file chunk that it represents. 181373ccdb9cSArgyrios Kyrtzidis 181473ccdb9cSArgyrios Kyrtzidis FileID SpellFID; // Current FileID in the spelling range. 181573ccdb9cSArgyrios Kyrtzidis unsigned SpellRelativeOffs; 1816867ea1d4SBenjamin Kramer std::tie(SpellFID, SpellRelativeOffs) = getDecomposedLoc(SpellLoc); 1817918e0ca7SEugene Zelenko while (true) { 181873ccdb9cSArgyrios Kyrtzidis const SLocEntry &Entry = getSLocEntry(SpellFID); 181973ccdb9cSArgyrios Kyrtzidis unsigned SpellFIDBeginOffs = Entry.getOffset(); 182073ccdb9cSArgyrios Kyrtzidis unsigned SpellFIDSize = getFileIDSize(SpellFID); 182173ccdb9cSArgyrios Kyrtzidis unsigned SpellFIDEndOffs = SpellFIDBeginOffs + SpellFIDSize; 182273ccdb9cSArgyrios Kyrtzidis const ExpansionInfo &Info = Entry.getExpansion(); 182373ccdb9cSArgyrios Kyrtzidis if (Info.isMacroArgExpansion()) { 182473ccdb9cSArgyrios Kyrtzidis unsigned CurrSpellLength; 182573ccdb9cSArgyrios Kyrtzidis if (SpellFIDEndOffs < SpellEndOffs) 182673ccdb9cSArgyrios Kyrtzidis CurrSpellLength = SpellFIDSize - SpellRelativeOffs; 182773ccdb9cSArgyrios Kyrtzidis else 182873ccdb9cSArgyrios Kyrtzidis CurrSpellLength = ExpansionLength; 182973ccdb9cSArgyrios Kyrtzidis associateFileChunkWithMacroArgExp(MacroArgsCache, FID, 183073ccdb9cSArgyrios Kyrtzidis Info.getSpellingLoc().getLocWithOffset(SpellRelativeOffs), 183173ccdb9cSArgyrios Kyrtzidis ExpansionLoc, CurrSpellLength); 183273ccdb9cSArgyrios Kyrtzidis } 183373ccdb9cSArgyrios Kyrtzidis 183473ccdb9cSArgyrios Kyrtzidis if (SpellFIDEndOffs >= SpellEndOffs) 183573ccdb9cSArgyrios Kyrtzidis return; // we covered all FileID entries in the spelling range. 183673ccdb9cSArgyrios Kyrtzidis 183773ccdb9cSArgyrios Kyrtzidis // Move to the next FileID entry in the spelling range. 183873ccdb9cSArgyrios Kyrtzidis unsigned advance = SpellFIDSize - SpellRelativeOffs + 1; 183973ccdb9cSArgyrios Kyrtzidis ExpansionLoc = ExpansionLoc.getLocWithOffset(advance); 184073ccdb9cSArgyrios Kyrtzidis ExpansionLength -= advance; 184173ccdb9cSArgyrios Kyrtzidis ++SpellFID.ID; 184273ccdb9cSArgyrios Kyrtzidis SpellRelativeOffs = 0; 184373ccdb9cSArgyrios Kyrtzidis } 184473ccdb9cSArgyrios Kyrtzidis } 184573ccdb9cSArgyrios Kyrtzidis 184673ccdb9cSArgyrios Kyrtzidis assert(SpellLoc.isFileID()); 1847e841c901SArgyrios Kyrtzidis 184861ef3db2SArgyrios Kyrtzidis unsigned BeginOffs; 184961ef3db2SArgyrios Kyrtzidis if (!isInFileID(SpellLoc, FID, &BeginOffs)) 185073ccdb9cSArgyrios Kyrtzidis return; 1851e841c901SArgyrios Kyrtzidis 185273ccdb9cSArgyrios Kyrtzidis unsigned EndOffs = BeginOffs + ExpansionLength; 185361ef3db2SArgyrios Kyrtzidis 185461ef3db2SArgyrios Kyrtzidis // Add a new chunk for this macro argument. A previous macro argument chunk 185561ef3db2SArgyrios Kyrtzidis // may have been lexed again, so e.g. if the map is 185661ef3db2SArgyrios Kyrtzidis // 0 -> SourceLocation() 185761ef3db2SArgyrios Kyrtzidis // 100 -> Expanded loc #1 185861ef3db2SArgyrios Kyrtzidis // 110 -> SourceLocation() 18592a8c18d9SAlexander Kornienko // and we found a new macro FileID that lexed from offset 105 with length 3, 186061ef3db2SArgyrios Kyrtzidis // the new map will be: 186161ef3db2SArgyrios Kyrtzidis // 0 -> SourceLocation() 186261ef3db2SArgyrios Kyrtzidis // 100 -> Expanded loc #1 186361ef3db2SArgyrios Kyrtzidis // 105 -> Expanded loc #2 186461ef3db2SArgyrios Kyrtzidis // 108 -> Expanded loc #1 186561ef3db2SArgyrios Kyrtzidis // 110 -> SourceLocation() 186661ef3db2SArgyrios Kyrtzidis // 186761ef3db2SArgyrios Kyrtzidis // Since re-lexed macro chunks will always be the same size or less of 186861ef3db2SArgyrios Kyrtzidis // previous chunks, we only need to find where the ending of the new macro 186961ef3db2SArgyrios Kyrtzidis // chunk is mapped to and update the map with new begin/end mappings. 187061ef3db2SArgyrios Kyrtzidis 18714bdd6aa1SArgyrios Kyrtzidis MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs); 187261ef3db2SArgyrios Kyrtzidis --I; 187361ef3db2SArgyrios Kyrtzidis SourceLocation EndOffsMappedLoc = I->second; 187473ccdb9cSArgyrios Kyrtzidis MacroArgsCache[BeginOffs] = ExpansionLoc; 187561ef3db2SArgyrios Kyrtzidis MacroArgsCache[EndOffs] = EndOffsMappedLoc; 187661ef3db2SArgyrios Kyrtzidis } 187761ef3db2SArgyrios Kyrtzidis 18789fc8faf9SAdrian Prantl /// If \arg Loc points inside a function macro argument, the returned 187992a47bd9SArgyrios Kyrtzidis /// location will be the macro location in which the argument was expanded. 188092a47bd9SArgyrios Kyrtzidis /// If a macro argument is used multiple times, the expanded location will 188192a47bd9SArgyrios Kyrtzidis /// be at the first expansion of the argument. 188292a47bd9SArgyrios Kyrtzidis /// e.g. 188392a47bd9SArgyrios Kyrtzidis /// MY_MACRO(foo); 188492a47bd9SArgyrios Kyrtzidis /// ^ 188592a47bd9SArgyrios Kyrtzidis /// Passing a file location pointing at 'foo', will yield a macro location 188692a47bd9SArgyrios Kyrtzidis /// where 'foo' was expanded into. 18877c06d866SArgyrios Kyrtzidis SourceLocation 18887c06d866SArgyrios Kyrtzidis SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) const { 188961ef3db2SArgyrios Kyrtzidis if (Loc.isInvalid() || !Loc.isFileID()) 189092a47bd9SArgyrios Kyrtzidis return Loc; 189192a47bd9SArgyrios Kyrtzidis 189261ef3db2SArgyrios Kyrtzidis FileID FID; 189361ef3db2SArgyrios Kyrtzidis unsigned Offset; 1894867ea1d4SBenjamin Kramer std::tie(FID, Offset) = getDecomposedLoc(Loc); 189592a47bd9SArgyrios Kyrtzidis if (FID.isInvalid()) 189692a47bd9SArgyrios Kyrtzidis return Loc; 189792a47bd9SArgyrios Kyrtzidis 1898d2c6a6d1SVedant Kumar std::unique_ptr<MacroArgsMap> &MacroArgsCache = MacroArgsCacheMap[FID]; 1899d2c6a6d1SVedant Kumar if (!MacroArgsCache) { 19002b3d49b6SJonas Devlieghere MacroArgsCache = std::make_unique<MacroArgsMap>(); 1901ecc31440SVedant Kumar computeMacroArgsCache(*MacroArgsCache, FID); 1902d2c6a6d1SVedant Kumar } 190392a47bd9SArgyrios Kyrtzidis 19044bdd6aa1SArgyrios Kyrtzidis assert(!MacroArgsCache->empty()); 19054bdd6aa1SArgyrios Kyrtzidis MacroArgsMap::iterator I = MacroArgsCache->upper_bound(Offset); 1906ae726fecSJan Korous // In case every element in MacroArgsCache is greater than Offset we can't 1907ae726fecSJan Korous // decrement the iterator. 1908ae726fecSJan Korous if (I == MacroArgsCache->begin()) 1909ae726fecSJan Korous return Loc; 1910ae726fecSJan Korous 191161ef3db2SArgyrios Kyrtzidis --I; 191261ef3db2SArgyrios Kyrtzidis 191361ef3db2SArgyrios Kyrtzidis unsigned MacroArgBeginOffs = I->first; 191461ef3db2SArgyrios Kyrtzidis SourceLocation MacroArgExpandedLoc = I->second; 191561ef3db2SArgyrios Kyrtzidis if (MacroArgExpandedLoc.isValid()) 1916e6e67deeSArgyrios Kyrtzidis return MacroArgExpandedLoc.getLocWithOffset(Offset - MacroArgBeginOffs); 191761ef3db2SArgyrios Kyrtzidis 191892a47bd9SArgyrios Kyrtzidis return Loc; 191992a47bd9SArgyrios Kyrtzidis } 192092a47bd9SArgyrios Kyrtzidis 192137613a9cSArgyrios Kyrtzidis std::pair<FileID, unsigned> 192237613a9cSArgyrios Kyrtzidis SourceManager::getDecomposedIncludedLoc(FileID FID) const { 19235dca8643SArgyrios Kyrtzidis if (FID.isInvalid()) 19245dca8643SArgyrios Kyrtzidis return std::make_pair(FileID(), 0); 19255dca8643SArgyrios Kyrtzidis 192637613a9cSArgyrios Kyrtzidis // Uses IncludedLocMap to retrieve/cache the decomposed loc. 192737613a9cSArgyrios Kyrtzidis 1928918e0ca7SEugene Zelenko using DecompTy = std::pair<FileID, unsigned>; 1929eae2b49fSFangrui Song auto InsertOp = IncludedLocMap.try_emplace(FID); 193037613a9cSArgyrios Kyrtzidis DecompTy &DecompLoc = InsertOp.first->second; 193137613a9cSArgyrios Kyrtzidis if (!InsertOp.second) 193237613a9cSArgyrios Kyrtzidis return DecompLoc; // already in map. 193337613a9cSArgyrios Kyrtzidis 193437613a9cSArgyrios Kyrtzidis SourceLocation UpperLoc; 19355dca8643SArgyrios Kyrtzidis bool Invalid = false; 19365dca8643SArgyrios Kyrtzidis const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); 19375dca8643SArgyrios Kyrtzidis if (!Invalid) { 193837613a9cSArgyrios Kyrtzidis if (Entry.isExpansion()) 193937613a9cSArgyrios Kyrtzidis UpperLoc = Entry.getExpansion().getExpansionLocStart(); 194037613a9cSArgyrios Kyrtzidis else 194137613a9cSArgyrios Kyrtzidis UpperLoc = Entry.getFile().getIncludeLoc(); 19425dca8643SArgyrios Kyrtzidis } 194337613a9cSArgyrios Kyrtzidis 194437613a9cSArgyrios Kyrtzidis if (UpperLoc.isValid()) 194537613a9cSArgyrios Kyrtzidis DecompLoc = getDecomposedLoc(UpperLoc); 194637613a9cSArgyrios Kyrtzidis 194737613a9cSArgyrios Kyrtzidis return DecompLoc; 194837613a9cSArgyrios Kyrtzidis } 194937613a9cSArgyrios Kyrtzidis 195064ee782eSChandler Carruth /// Given a decomposed source location, move it up the include/expansion stack 195164ee782eSChandler Carruth /// to the parent source location. If this is possible, return the decomposed 195264ee782eSChandler Carruth /// version of the parent in Loc and return false. If Loc is the top-level 195364ee782eSChandler Carruth /// entry, return true and don't modify it. 1954a99fa1aeSChris Lattner static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc, 1955a99fa1aeSChris Lattner const SourceManager &SM) { 195637613a9cSArgyrios Kyrtzidis std::pair<FileID, unsigned> UpperLoc = SM.getDecomposedIncludedLoc(Loc.first); 195737613a9cSArgyrios Kyrtzidis if (UpperLoc.first.isInvalid()) 1958a99fa1aeSChris Lattner return true; // We reached the top. 1959a99fa1aeSChris Lattner 196037613a9cSArgyrios Kyrtzidis Loc = UpperLoc; 1961a99fa1aeSChris Lattner return false; 1962a99fa1aeSChris Lattner } 1963a99fa1aeSChris Lattner 196408037045STed Kremenek /// Return the cache entry for comparing the given file IDs 196508037045STed Kremenek /// for isBeforeInTranslationUnit. 196608037045STed Kremenek InBeforeInTUCacheEntry &SourceManager::getInBeforeInTUCache(FileID LFID, 196708037045STed Kremenek FileID RFID) const { 196808037045STed Kremenek // This is a magic number for limiting the cache size. It was experimentally 196908037045STed Kremenek // derived from a small Objective-C project (where the cache filled 197008037045STed Kremenek // out to ~250 items). We can make it larger if necessary. 197108037045STed Kremenek enum { MagicCacheSize = 300 }; 197208037045STed Kremenek IsBeforeInTUCacheKey Key(LFID, RFID); 197308037045STed Kremenek 197408037045STed Kremenek // If the cache size isn't too large, do a lookup and if necessary default 197508037045STed Kremenek // construct an entry. We can then return it to the caller for direct 197608037045STed Kremenek // use. When they update the value, the cache will get automatically 197708037045STed Kremenek // updated as well. 197808037045STed Kremenek if (IBTUCache.size() < MagicCacheSize) 197908037045STed Kremenek return IBTUCache[Key]; 198008037045STed Kremenek 198108037045STed Kremenek // Otherwise, do a lookup that will not construct a new value. 198208037045STed Kremenek InBeforeInTUCache::iterator I = IBTUCache.find(Key); 198308037045STed Kremenek if (I != IBTUCache.end()) 198408037045STed Kremenek return I->second; 198508037045STed Kremenek 198608037045STed Kremenek // Fall back to the overflow value. 198708037045STed Kremenek return IBTUCacheOverflow; 198808037045STed Kremenek } 1989a99fa1aeSChris Lattner 19909fc8faf9SAdrian Prantl /// Determines the order of 2 source locations in the translation unit. 199133661d9fSArgyrios Kyrtzidis /// 199233661d9fSArgyrios Kyrtzidis /// \returns true if LHS source location comes before RHS, false otherwise. 199333661d9fSArgyrios Kyrtzidis bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, 199433661d9fSArgyrios Kyrtzidis SourceLocation RHS) const { 199533661d9fSArgyrios Kyrtzidis assert(LHS.isValid() && RHS.isValid() && "Passed invalid source location!"); 199633661d9fSArgyrios Kyrtzidis if (LHS == RHS) 199733661d9fSArgyrios Kyrtzidis return false; 199833661d9fSArgyrios Kyrtzidis 199933661d9fSArgyrios Kyrtzidis std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS); 200033661d9fSArgyrios Kyrtzidis std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS); 200133661d9fSArgyrios Kyrtzidis 20025fd822c2SArgyrios Kyrtzidis // getDecomposedLoc may have failed to return a valid FileID because, e.g. it 20035fd822c2SArgyrios Kyrtzidis // is a serialized one referring to a file that was removed after we loaded 20045fd822c2SArgyrios Kyrtzidis // the PCH. 20055dca8643SArgyrios Kyrtzidis if (LOffs.first.isInvalid() || ROffs.first.isInvalid()) 2006d6111d3cSArgyrios Kyrtzidis return LOffs.first.isInvalid() && !ROffs.first.isInvalid(); 20075dca8643SArgyrios Kyrtzidis 20087848b388SGabor Horvath std::pair<bool, bool> InSameTU = isInTheSameTranslationUnit(LOffs, ROffs); 20097848b388SGabor Horvath if (InSameTU.first) 20107848b388SGabor Horvath return InSameTU.second; 201133661d9fSArgyrios Kyrtzidis 20121d3b431cSJoerg Sonnenberger // If we arrived here, the location is either in a built-ins buffer or 20131d3b431cSJoerg Sonnenberger // associated with global inline asm. PR5662 and PR22576 are examples. 20141d3b431cSJoerg Sonnenberger 201554c1bcabSDuncan P. N. Exon Smith StringRef LB = getBufferOrFake(LOffs.first).getBufferIdentifier(); 201654c1bcabSDuncan P. N. Exon Smith StringRef RB = getBufferOrFake(ROffs.first).getBufferIdentifier(); 201799d1b295SMehdi Amini bool LIsBuiltins = LB == "<built-in>"; 201899d1b295SMehdi Amini bool RIsBuiltins = RB == "<built-in>"; 20191d3b431cSJoerg Sonnenberger // Sort built-in before non-built-in. 20201d3b431cSJoerg Sonnenberger if (LIsBuiltins || RIsBuiltins) { 2021925296b4SDouglas Gregor if (LIsBuiltins != RIsBuiltins) 2022925296b4SDouglas Gregor return LIsBuiltins; 2023925296b4SDouglas Gregor // Both are in built-in buffers, but from different files. We just claim that 2024925296b4SDouglas Gregor // lower IDs come first. 202566d2f924SChris Lattner return LOffs.first < ROffs.first; 202633661d9fSArgyrios Kyrtzidis } 202799d1b295SMehdi Amini bool LIsAsm = LB == "<inline asm>"; 202899d1b295SMehdi Amini bool RIsAsm = RB == "<inline asm>"; 20291d3b431cSJoerg Sonnenberger // Sort assembler after built-ins, but before the rest. 20301d3b431cSJoerg Sonnenberger if (LIsAsm || RIsAsm) { 20311d3b431cSJoerg Sonnenberger if (LIsAsm != RIsAsm) 20321d3b431cSJoerg Sonnenberger return RIsAsm; 20331d3b431cSJoerg Sonnenberger assert(LOffs.first == ROffs.first); 20341d3b431cSJoerg Sonnenberger return false; 20351d3b431cSJoerg Sonnenberger } 203699d1b295SMehdi Amini bool LIsScratch = LB == "<scratch space>"; 203799d1b295SMehdi Amini bool RIsScratch = RB == "<scratch space>"; 2038154e57f8SYury Gribov // Sort scratch after inline asm, but before the rest. 2039154e57f8SYury Gribov if (LIsScratch || RIsScratch) { 2040154e57f8SYury Gribov if (LIsScratch != RIsScratch) 2041154e57f8SYury Gribov return LIsScratch; 2042154e57f8SYury Gribov return LOffs.second < ROffs.second; 2043154e57f8SYury Gribov } 20441d3b431cSJoerg Sonnenberger llvm_unreachable("Unsortable locations found"); 20451d3b431cSJoerg Sonnenberger } 20464fa23625SChris Lattner 20477848b388SGabor Horvath std::pair<bool, bool> SourceManager::isInTheSameTranslationUnit( 20487848b388SGabor Horvath std::pair<FileID, unsigned> &LOffs, 20497848b388SGabor Horvath std::pair<FileID, unsigned> &ROffs) const { 20507848b388SGabor Horvath // If the source locations are in the same file, just compare offsets. 20517848b388SGabor Horvath if (LOffs.first == ROffs.first) 20527848b388SGabor Horvath return std::make_pair(true, LOffs.second < ROffs.second); 20537848b388SGabor Horvath 20547848b388SGabor Horvath // If we are comparing a source location with multiple locations in the same 20557848b388SGabor Horvath // file, we get a big win by caching the result. 20567848b388SGabor Horvath InBeforeInTUCacheEntry &IsBeforeInTUCache = 20577848b388SGabor Horvath getInBeforeInTUCache(LOffs.first, ROffs.first); 20587848b388SGabor Horvath 20597848b388SGabor Horvath // If we are comparing a source location with multiple locations in the same 20607848b388SGabor Horvath // file, we get a big win by caching the result. 20617848b388SGabor Horvath if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first)) 20627848b388SGabor Horvath return std::make_pair( 20637848b388SGabor Horvath true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second)); 20647848b388SGabor Horvath 20657848b388SGabor Horvath // Okay, we missed in the cache, start updating the cache for this query. 20667848b388SGabor Horvath IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first, 20677848b388SGabor Horvath /*isLFIDBeforeRFID=*/LOffs.first.ID < ROffs.first.ID); 20687848b388SGabor Horvath 20697848b388SGabor Horvath // We need to find the common ancestor. The only way of doing this is to 20707848b388SGabor Horvath // build the complete include chain for one and then walking up the chain 20717848b388SGabor Horvath // of the other looking for a match. 20727848b388SGabor Horvath // We use a map from FileID to Offset to store the chain. Easier than writing 20737848b388SGabor Horvath // a custom set hash info that only depends on the first part of a pair. 2074918e0ca7SEugene Zelenko using LocSet = llvm::SmallDenseMap<FileID, unsigned, 16>; 20757848b388SGabor Horvath LocSet LChain; 20767848b388SGabor Horvath do { 20777848b388SGabor Horvath LChain.insert(LOffs); 20787848b388SGabor Horvath // We catch the case where LOffs is in a file included by ROffs and 20797848b388SGabor Horvath // quit early. The other way round unfortunately remains suboptimal. 20807848b388SGabor Horvath } while (LOffs.first != ROffs.first && !MoveUpIncludeHierarchy(LOffs, *this)); 20817848b388SGabor Horvath LocSet::iterator I; 20827848b388SGabor Horvath while((I = LChain.find(ROffs.first)) == LChain.end()) { 20837848b388SGabor Horvath if (MoveUpIncludeHierarchy(ROffs, *this)) 20847848b388SGabor Horvath break; // Met at topmost file. 20857848b388SGabor Horvath } 20867848b388SGabor Horvath if (I != LChain.end()) 20877848b388SGabor Horvath LOffs = *I; 20887848b388SGabor Horvath 20897848b388SGabor Horvath // If we exited because we found a nearest common ancestor, compare the 20907848b388SGabor Horvath // locations within the common file and cache them. 20917848b388SGabor Horvath if (LOffs.first == ROffs.first) { 20927848b388SGabor Horvath IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second); 20937848b388SGabor Horvath return std::make_pair( 20947848b388SGabor Horvath true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second)); 20957848b388SGabor Horvath } 20967848b388SGabor Horvath // Clear the lookup cache, it depends on a common location. 20977848b388SGabor Horvath IsBeforeInTUCache.clear(); 20987848b388SGabor Horvath return std::make_pair(false, false); 20997848b388SGabor Horvath } 21007848b388SGabor Horvath 21017a51313dSChris Lattner void SourceManager::PrintStats() const { 210289b422c1SBenjamin Kramer llvm::errs() << "\n*** Source Manager Stats:\n"; 210389b422c1SBenjamin Kramer llvm::errs() << FileInfos.size() << " files mapped, " << MemBufferInfos.size() 21046d61c3e6SChris Lattner << " mem buffers mapped.\n"; 2105925296b4SDouglas Gregor llvm::errs() << LocalSLocEntryTable.size() << " local SLocEntry's allocated (" 210643e0c4a8STed Kremenek << llvm::capacity_in_bytes(LocalSLocEntryTable) 21072cc62093SArgyrios Kyrtzidis << " bytes of capacity), " 2108925296b4SDouglas Gregor << NextLocalOffset << "B of Sloc address space used.\n"; 2109925296b4SDouglas Gregor llvm::errs() << LoadedSLocEntryTable.size() 2110925296b4SDouglas Gregor << " loaded SLocEntries allocated, " 211192a47bd9SArgyrios Kyrtzidis << MaxLoadedOffset - CurrentLoadedOffset 2112925296b4SDouglas Gregor << "B of Sloc address space used.\n"; 21137a51313dSChris Lattner 21147a51313dSChris Lattner unsigned NumLineNumsComputed = 0; 21157a51313dSChris Lattner unsigned NumFileBytesMapped = 0; 2116c8233df6SChris Lattner for (fileinfo_iterator I = fileinfo_begin(), E = fileinfo_end(); I != E; ++I){ 2117*dbbc4f4eSDuncan P. N. Exon Smith NumLineNumsComputed += bool(I->second->SourceLineCache); 2118c8233df6SChris Lattner NumFileBytesMapped += I->second->getSizeBytesMapped(); 21197a51313dSChris Lattner } 21204bdd6aa1SArgyrios Kyrtzidis unsigned NumMacroArgsComputed = MacroArgsCacheMap.size(); 21217a51313dSChris Lattner 212289b422c1SBenjamin Kramer llvm::errs() << NumFileBytesMapped << " bytes of files mapped, " 212361ef3db2SArgyrios Kyrtzidis << NumLineNumsComputed << " files with line #'s computed, " 212461ef3db2SArgyrios Kyrtzidis << NumMacroArgsComputed << " files with macro args computed.\n"; 212589b422c1SBenjamin Kramer llvm::errs() << "FileID scans: " << NumLinearScans << " linear, " 21264fa23625SChris Lattner << NumBinaryProbes << " binary.\n"; 21277a51313dSChris Lattner } 2128258ae54aSDouglas Gregor 212903a06dd1SRichard Smith LLVM_DUMP_METHOD void SourceManager::dump() const { 213003a06dd1SRichard Smith llvm::raw_ostream &out = llvm::errs(); 213103a06dd1SRichard Smith 213203a06dd1SRichard Smith auto DumpSLocEntry = [&](int ID, const SrcMgr::SLocEntry &Entry, 213303a06dd1SRichard Smith llvm::Optional<unsigned> NextStart) { 213403a06dd1SRichard Smith out << "SLocEntry <FileID " << ID << "> " << (Entry.isFile() ? "file" : "expansion") 213503a06dd1SRichard Smith << " <SourceLocation " << Entry.getOffset() << ":"; 213603a06dd1SRichard Smith if (NextStart) 213703a06dd1SRichard Smith out << *NextStart << ">\n"; 213803a06dd1SRichard Smith else 213903a06dd1SRichard Smith out << "???\?>\n"; 214003a06dd1SRichard Smith if (Entry.isFile()) { 214103a06dd1SRichard Smith auto &FI = Entry.getFile(); 214203a06dd1SRichard Smith if (FI.NumCreatedFIDs) 214303a06dd1SRichard Smith out << " covers <FileID " << ID << ":" << int(ID + FI.NumCreatedFIDs) 214403a06dd1SRichard Smith << ">\n"; 214503a06dd1SRichard Smith if (FI.getIncludeLoc().isValid()) 214603a06dd1SRichard Smith out << " included from " << FI.getIncludeLoc().getOffset() << "\n"; 214774a87834SDuncan P. N. Exon Smith auto &CC = FI.getContentCache(); 214874a87834SDuncan P. N. Exon Smith out << " for " << (CC.OrigEntry ? CC.OrigEntry->getName() : "<none>") 214903a06dd1SRichard Smith << "\n"; 215074a87834SDuncan P. N. Exon Smith if (CC.BufferOverridden) 215103a06dd1SRichard Smith out << " contents overridden\n"; 215274a87834SDuncan P. N. Exon Smith if (CC.ContentsEntry != CC.OrigEntry) { 215303a06dd1SRichard Smith out << " contents from " 215474a87834SDuncan P. N. Exon Smith << (CC.ContentsEntry ? CC.ContentsEntry->getName() : "<none>") 215503a06dd1SRichard Smith << "\n"; 215603a06dd1SRichard Smith } 215703a06dd1SRichard Smith } else { 215803a06dd1SRichard Smith auto &EI = Entry.getExpansion(); 215903a06dd1SRichard Smith out << " spelling from " << EI.getSpellingLoc().getOffset() << "\n"; 216003a06dd1SRichard Smith out << " macro " << (EI.isMacroArgExpansion() ? "arg" : "body") 216103a06dd1SRichard Smith << " range <" << EI.getExpansionLocStart().getOffset() << ":" 216203a06dd1SRichard Smith << EI.getExpansionLocEnd().getOffset() << ">\n"; 216303a06dd1SRichard Smith } 216403a06dd1SRichard Smith }; 216503a06dd1SRichard Smith 216603a06dd1SRichard Smith // Dump local SLocEntries. 216703a06dd1SRichard Smith for (unsigned ID = 0, NumIDs = LocalSLocEntryTable.size(); ID != NumIDs; ++ID) { 216803a06dd1SRichard Smith DumpSLocEntry(ID, LocalSLocEntryTable[ID], 216903a06dd1SRichard Smith ID == NumIDs - 1 ? NextLocalOffset 217003a06dd1SRichard Smith : LocalSLocEntryTable[ID + 1].getOffset()); 217103a06dd1SRichard Smith } 217203a06dd1SRichard Smith // Dump loaded SLocEntries. 217303a06dd1SRichard Smith llvm::Optional<unsigned> NextStart; 217403a06dd1SRichard Smith for (unsigned Index = 0; Index != LoadedSLocEntryTable.size(); ++Index) { 217503a06dd1SRichard Smith int ID = -(int)Index - 2; 217603a06dd1SRichard Smith if (SLocEntryLoaded[Index]) { 217703a06dd1SRichard Smith DumpSLocEntry(ID, LoadedSLocEntryTable[Index], NextStart); 217803a06dd1SRichard Smith NextStart = LoadedSLocEntryTable[Index].getOffset(); 217903a06dd1SRichard Smith } else { 218003a06dd1SRichard Smith NextStart = None; 218103a06dd1SRichard Smith } 218203a06dd1SRichard Smith } 218303a06dd1SRichard Smith } 218403a06dd1SRichard Smith 2185918e0ca7SEugene Zelenko ExternalSLocEntrySource::~ExternalSLocEntrySource() = default; 21868d587900STed Kremenek 21878d587900STed Kremenek /// Return the amount of memory used by memory buffers, breaking down 21888d587900STed Kremenek /// by heap-backed versus mmap'ed memory. 21898d587900STed Kremenek SourceManager::MemoryBufferSizes SourceManager::getMemoryBufferSizes() const { 21908d587900STed Kremenek size_t malloc_bytes = 0; 21918d587900STed Kremenek size_t mmap_bytes = 0; 21928d587900STed Kremenek 21938d587900STed Kremenek for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i) 21948d587900STed Kremenek if (size_t sized_mapped = MemBufferInfos[i]->getSizeBytesMapped()) 21958d587900STed Kremenek switch (MemBufferInfos[i]->getMemoryBufferKind()) { 21968d587900STed Kremenek case llvm::MemoryBuffer::MemoryBuffer_MMap: 21978d587900STed Kremenek mmap_bytes += sized_mapped; 21988d587900STed Kremenek break; 21998d587900STed Kremenek case llvm::MemoryBuffer::MemoryBuffer_Malloc: 22008d587900STed Kremenek malloc_bytes += sized_mapped; 22018d587900STed Kremenek break; 22028d587900STed Kremenek } 22038d587900STed Kremenek 22048d587900STed Kremenek return MemoryBufferSizes(malloc_bytes, mmap_bytes); 22058d587900STed Kremenek } 22068d587900STed Kremenek 2207120992adSTed Kremenek size_t SourceManager::getDataStructureSizes() const { 22086eec06d0SArgyrios Kyrtzidis size_t size = llvm::capacity_in_bytes(MemBufferInfos) 220943e0c4a8STed Kremenek + llvm::capacity_in_bytes(LocalSLocEntryTable) 221043e0c4a8STed Kremenek + llvm::capacity_in_bytes(LoadedSLocEntryTable) 221143e0c4a8STed Kremenek + llvm::capacity_in_bytes(SLocEntryLoaded) 22126eec06d0SArgyrios Kyrtzidis + llvm::capacity_in_bytes(FileInfos); 22136eec06d0SArgyrios Kyrtzidis 22146eec06d0SArgyrios Kyrtzidis if (OverriddenFilesInfo) 22156eec06d0SArgyrios Kyrtzidis size += llvm::capacity_in_bytes(OverriddenFilesInfo->OverriddenFiles); 22166eec06d0SArgyrios Kyrtzidis 22176eec06d0SArgyrios Kyrtzidis return size; 2218120992adSTed Kremenek } 22192e538089SEric Liu 22202e538089SEric Liu SourceManagerForFile::SourceManagerForFile(StringRef FileName, 22212e538089SEric Liu StringRef Content) { 22222e538089SEric Liu // This is referenced by `FileMgr` and will be released by `FileMgr` when it 22232e538089SEric Liu // is deleted. 2224fc51490bSJonas Devlieghere IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 2225fc51490bSJonas Devlieghere new llvm::vfs::InMemoryFileSystem); 22262e538089SEric Liu InMemoryFileSystem->addFile( 22272e538089SEric Liu FileName, 0, 22282e538089SEric Liu llvm::MemoryBuffer::getMemBuffer(Content, FileName, 22292e538089SEric Liu /*RequiresNullTerminator=*/false)); 22302e538089SEric Liu // This is passed to `SM` as reference, so the pointer has to be referenced 22312e538089SEric Liu // in `Environment` so that `FileMgr` can out-live this function scope. 22322e538089SEric Liu FileMgr = 22332b3d49b6SJonas Devlieghere std::make_unique<FileManager>(FileSystemOptions(), InMemoryFileSystem); 22342e538089SEric Liu // This is passed to `SM` as reference, so the pointer has to be referenced 22352e538089SEric Liu // by `Environment` due to the same reason above. 22362b3d49b6SJonas Devlieghere Diagnostics = std::make_unique<DiagnosticsEngine>( 22372e538089SEric Liu IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), 22382e538089SEric Liu new DiagnosticOptions); 22392b3d49b6SJonas Devlieghere SourceMgr = std::make_unique<SourceManager>(*Diagnostics, *FileMgr); 22408d323d15SHarlan Haskins FileID ID = SourceMgr->createFileID(*FileMgr->getFile(FileName), 22412e538089SEric Liu SourceLocation(), clang::SrcMgr::C_User); 22422e538089SEric Liu assert(ID.isValid()); 22432e538089SEric Liu SourceMgr->setMainFileID(ID); 22442e538089SEric Liu } 2245