SourceMgr.cpp revision 202878
1194612Sed//===- SourceMgr.cpp - Manager for Simple Source Buffers & Diagnostics ----===// 2194612Sed// 3194612Sed// The LLVM Compiler Infrastructure 4194612Sed// 5194612Sed// This file is distributed under the University of Illinois Open Source 6194612Sed// License. See LICENSE.TXT for details. 7194612Sed// 8194612Sed//===----------------------------------------------------------------------===// 9194612Sed// 10194612Sed// This file implements the SourceMgr class. This class is used as a simple 11194612Sed// substrate for diagnostics, #include handling, and other low level things for 12194612Sed// simple parsers. 13194612Sed// 14194612Sed//===----------------------------------------------------------------------===// 15194612Sed 16194612Sed#include "llvm/Support/SourceMgr.h" 17194612Sed#include "llvm/Support/MemoryBuffer.h" 18194612Sed#include "llvm/Support/raw_ostream.h" 19194612Sedusing namespace llvm; 20194612Sed 21198090Srdivackynamespace { 22198090Srdivacky struct LineNoCacheTy { 23198090Srdivacky int LastQueryBufferID; 24198090Srdivacky const char *LastQuery; 25198090Srdivacky unsigned LineNoOfQuery; 26198090Srdivacky }; 27198090Srdivacky} 28198090Srdivacky 29198090Srdivackystatic LineNoCacheTy *getCache(void *Ptr) { 30198090Srdivacky return (LineNoCacheTy*)Ptr; 31198090Srdivacky} 32198090Srdivacky 33198090Srdivacky 34194612SedSourceMgr::~SourceMgr() { 35198090Srdivacky // Delete the line # cache if allocated. 36198090Srdivacky if (LineNoCacheTy *Cache = getCache(LineNoCache)) 37198090Srdivacky delete Cache; 38198090Srdivacky 39194612Sed while (!Buffers.empty()) { 40194612Sed delete Buffers.back().Buffer; 41194612Sed Buffers.pop_back(); 42194612Sed } 43194612Sed} 44194612Sed 45194612Sed/// AddIncludeFile - Search for a file with the specified name in the current 46194612Sed/// directory or in one of the IncludeDirs. If no file is found, this returns 47194612Sed/// ~0, otherwise it returns the buffer ID of the stacked file. 48194612Sedunsigned SourceMgr::AddIncludeFile(const std::string &Filename, 49194612Sed SMLoc IncludeLoc) { 50194612Sed 51194612Sed MemoryBuffer *NewBuf = MemoryBuffer::getFile(Filename.c_str()); 52194612Sed 53194612Sed // If the file didn't exist directly, see if it's in an include path. 54194612Sed for (unsigned i = 0, e = IncludeDirectories.size(); i != e && !NewBuf; ++i) { 55194612Sed std::string IncFile = IncludeDirectories[i] + "/" + Filename; 56194612Sed NewBuf = MemoryBuffer::getFile(IncFile.c_str()); 57194612Sed } 58194612Sed 59194612Sed if (NewBuf == 0) return ~0U; 60194612Sed 61194612Sed return AddNewSourceBuffer(NewBuf, IncludeLoc); 62194612Sed} 63194612Sed 64194612Sed 65194612Sed/// FindBufferContainingLoc - Return the ID of the buffer containing the 66194612Sed/// specified location, returning -1 if not found. 67194612Sedint SourceMgr::FindBufferContainingLoc(SMLoc Loc) const { 68194612Sed for (unsigned i = 0, e = Buffers.size(); i != e; ++i) 69194612Sed if (Loc.getPointer() >= Buffers[i].Buffer->getBufferStart() && 70194612Sed // Use <= here so that a pointer to the null at the end of the buffer 71194612Sed // is included as part of the buffer. 72194612Sed Loc.getPointer() <= Buffers[i].Buffer->getBufferEnd()) 73194612Sed return i; 74194612Sed return -1; 75194612Sed} 76194612Sed 77194612Sed/// FindLineNumber - Find the line number for the specified location in the 78194612Sed/// specified file. This is not a fast method. 79194612Sedunsigned SourceMgr::FindLineNumber(SMLoc Loc, int BufferID) const { 80194612Sed if (BufferID == -1) BufferID = FindBufferContainingLoc(Loc); 81194612Sed assert(BufferID != -1 && "Invalid Location!"); 82194612Sed 83194612Sed MemoryBuffer *Buff = getBufferInfo(BufferID).Buffer; 84194612Sed 85194612Sed // Count the number of \n's between the start of the file and the specified 86194612Sed // location. 87194612Sed unsigned LineNo = 1; 88194612Sed 89194612Sed const char *Ptr = Buff->getBufferStart(); 90194612Sed 91198090Srdivacky // If we have a line number cache, and if the query is to a later point in the 92198090Srdivacky // same file, start searching from the last query location. This optimizes 93198090Srdivacky // for the case when multiple diagnostics come out of one file in order. 94198090Srdivacky if (LineNoCacheTy *Cache = getCache(LineNoCache)) 95198090Srdivacky if (Cache->LastQueryBufferID == BufferID && 96198090Srdivacky Cache->LastQuery <= Loc.getPointer()) { 97198090Srdivacky Ptr = Cache->LastQuery; 98198090Srdivacky LineNo = Cache->LineNoOfQuery; 99198090Srdivacky } 100198090Srdivacky 101198090Srdivacky // Scan for the location being queried, keeping track of the number of lines 102198090Srdivacky // we see. 103194612Sed for (; SMLoc::getFromPointer(Ptr) != Loc; ++Ptr) 104194612Sed if (*Ptr == '\n') ++LineNo; 105198090Srdivacky 106198090Srdivacky 107198090Srdivacky // Allocate the line number cache if it doesn't exist. 108198090Srdivacky if (LineNoCache == 0) 109198090Srdivacky LineNoCache = new LineNoCacheTy(); 110198090Srdivacky 111198090Srdivacky // Update the line # cache. 112198090Srdivacky LineNoCacheTy &Cache = *getCache(LineNoCache); 113198090Srdivacky Cache.LastQueryBufferID = BufferID; 114198090Srdivacky Cache.LastQuery = Ptr; 115198090Srdivacky Cache.LineNoOfQuery = LineNo; 116194612Sed return LineNo; 117194612Sed} 118194612Sed 119195340Sedvoid SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const { 120194612Sed if (IncludeLoc == SMLoc()) return; // Top of stack. 121194612Sed 122194612Sed int CurBuf = FindBufferContainingLoc(IncludeLoc); 123194612Sed assert(CurBuf != -1 && "Invalid or unspecified location!"); 124194612Sed 125195340Sed PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS); 126194612Sed 127195340Sed OS << "Included from " 128195340Sed << getBufferInfo(CurBuf).Buffer->getBufferIdentifier() 129195340Sed << ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n"; 130194612Sed} 131194612Sed 132194612Sed 133195340Sed/// GetMessage - Return an SMDiagnostic at the specified location with the 134195340Sed/// specified string. 135195340Sed/// 136195340Sed/// @param Type - If non-null, the kind of message (e.g., "error") which is 137195340Sed/// prefixed to the message. 138195340SedSMDiagnostic SourceMgr::GetMessage(SMLoc Loc, const std::string &Msg, 139199989Srdivacky const char *Type, bool ShowLine) const { 140194612Sed 141194612Sed // First thing to do: find the current buffer containing the specified 142194612Sed // location. 143194612Sed int CurBuf = FindBufferContainingLoc(Loc); 144194612Sed assert(CurBuf != -1 && "Invalid or unspecified location!"); 145194612Sed 146194612Sed MemoryBuffer *CurMB = getBufferInfo(CurBuf).Buffer; 147199989Srdivacky 148194612Sed // Scan backward to find the start of the line. 149194612Sed const char *LineStart = Loc.getPointer(); 150199989Srdivacky while (LineStart != CurMB->getBufferStart() && 151194612Sed LineStart[-1] != '\n' && LineStart[-1] != '\r') 152194612Sed --LineStart; 153199989Srdivacky 154199989Srdivacky std::string LineStr; 155199989Srdivacky if (ShowLine) { 156199989Srdivacky // Get the end of the line. 157199989Srdivacky const char *LineEnd = Loc.getPointer(); 158199989Srdivacky while (LineEnd != CurMB->getBufferEnd() && 159199989Srdivacky LineEnd[0] != '\n' && LineEnd[0] != '\r') 160199989Srdivacky ++LineEnd; 161199989Srdivacky LineStr = std::string(LineStart, LineEnd); 162199989Srdivacky } 163195340Sed 164195340Sed std::string PrintedMsg; 165195340Sed if (Type) { 166195340Sed PrintedMsg = Type; 167195340Sed PrintedMsg += ": "; 168195340Sed } 169195340Sed PrintedMsg += Msg; 170199989Srdivacky 171195340Sed return SMDiagnostic(CurMB->getBufferIdentifier(), FindLineNumber(Loc, CurBuf), 172195340Sed Loc.getPointer()-LineStart, PrintedMsg, 173199989Srdivacky LineStr, ShowLine); 174194612Sed} 175195340Sed 176195340Sedvoid SourceMgr::PrintMessage(SMLoc Loc, const std::string &Msg, 177199989Srdivacky const char *Type, bool ShowLine) const { 178195340Sed raw_ostream &OS = errs(); 179195340Sed 180195340Sed int CurBuf = FindBufferContainingLoc(Loc); 181195340Sed assert(CurBuf != -1 && "Invalid or unspecified location!"); 182195340Sed PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS); 183195340Sed 184199989Srdivacky GetMessage(Loc, Msg, Type, ShowLine).Print(0, OS); 185195340Sed} 186195340Sed 187195340Sed//===----------------------------------------------------------------------===// 188195340Sed// SMDiagnostic Implementation 189195340Sed//===----------------------------------------------------------------------===// 190195340Sed 191195340Sedvoid SMDiagnostic::Print(const char *ProgName, raw_ostream &S) { 192195340Sed if (ProgName && ProgName[0]) 193195340Sed S << ProgName << ": "; 194195340Sed 195202878Srdivacky if (!Filename.empty()) { 196202878Srdivacky if (Filename == "-") 197202878Srdivacky S << "<stdin>"; 198202878Srdivacky else 199202878Srdivacky S << Filename; 200195340Sed 201202878Srdivacky if (LineNo != -1) { 202202878Srdivacky S << ':' << LineNo; 203202878Srdivacky if (ColumnNo != -1) 204202878Srdivacky S << ':' << (ColumnNo+1); 205202878Srdivacky } 206202878Srdivacky S << ": "; 207195340Sed } 208195340Sed 209202878Srdivacky S << Message << '\n'; 210199989Srdivacky 211199989Srdivacky if (LineNo != -1 && ColumnNo != -1 && ShowLine) { 212195340Sed S << LineContents << '\n'; 213195340Sed 214195340Sed // Print out spaces/tabs before the caret. 215195340Sed for (unsigned i = 0; i != unsigned(ColumnNo); ++i) 216195340Sed S << (LineContents[i] == '\t' ? '\t' : ' '); 217195340Sed S << "^\n"; 218195340Sed } 219195340Sed} 220195340Sed 221195340Sed 222